Skip to content

Commit

Permalink
GUI improvements and bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
andreasgriffin committed Jul 24, 2024
1 parent 785ad36 commit f766f69
Show file tree
Hide file tree
Showing 23 changed files with 764 additions and 314 deletions.
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ repos:
- types-toml


- repo: local
hooks:
- id: update-poetry-version
name: Update Poetry Version
entry: python .update_version.py
language: python
always_run: true
files: pyproject.toml
additional_dependencies:
- toml

# - repo: https://github.com/PyCQA/bandit
# rev: 1.7.6 # Use the latest version
Expand Down
50 changes: 50 additions & 0 deletions .update_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#
# Bitcoin Safe
# Copyright (C) 2024 Andreas Griffin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of version 3 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.html
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import toml

from bitcoin_safe import __version__


def update_poetry_version(file_path, new_version):
# Read the pyproject.toml file
with open(file_path, "r") as file:
data = toml.load(file)

# Update the version under tool.poetry
if "tool" in data and "poetry" in data["tool"] and "version" in data["tool"]["poetry"]:
data["tool"]["poetry"]["version"] = new_version
# Write the updated data back to pyproject.toml
with open(file_path, "w") as file:
toml.dump(data, file)
print(f"Version updated to {new_version} in pyproject.toml")
else:
print("Could not find the 'tool.poetry.version' key in the pyproject.toml")


update_poetry_version("pyproject.toml", __version__)
3 changes: 2 additions & 1 deletion bitcoin_safe/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
__version__ = "0.7.1a0"
# this is the source of the version information
__version__ = "0.7.2a0"
141 changes: 83 additions & 58 deletions bitcoin_safe/gui/qt/address_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,79 @@


import logging
import typing

from bitcoin_qr_tools.qr_widgets import QRCodeWidgetSVG

from bitcoin_safe.config import UserConfig
from bitcoin_safe.gui.qt.buttonedit import ButtonEdit
from bitcoin_safe.gui.qt.recipients import RecipientTabWidget
from bitcoin_safe.mempool import MempoolData
from bitcoin_safe.util import serialized_to_hex

logger = logging.getLogger(__name__)

import bdkpython as bdk
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QKeyEvent
from PyQt6.QtWidgets import (
QFormLayout,
QHBoxLayout,
QLabel,
QSizePolicy,
QTabWidget,
QTextEdit,
QVBoxLayout,
QWidget,
)

from ...signals import Signals
from ...wallet import Wallet
from .hist_list import HistList, HistListWithToolbar
from .hist_list import HistList
from .util import Buttons, CloseButton


class AddressDetailsAdvanced(QWidget):
def __init__(
self, bdk_address: bdk.Address, address_path_str: str, parent: typing.Optional["QWidget"]
) -> None:
super().__init__(parent)

form_layout = QFormLayout(self)
form_layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)

try:
script_pubkey = serialized_to_hex(bdk_address.script_pubkey().to_bytes())
except BaseException:
script_pubkey = None
if script_pubkey:
pubkey_e = ButtonEdit(script_pubkey)
pubkey_e.button_container.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
pubkey_e.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)

pubkey_e.add_copy_button()
pubkey_e.setReadOnly(True)

form_layout.addRow(self.tr("Script Pubkey"), pubkey_e)

if address_path_str:
der_path_e = ButtonEdit(address_path_str, input_field=QTextEdit())
der_path_e.add_copy_button()
der_path_e.setFixedHeight(50)
der_path_e.setReadOnly(True)

form_layout.addRow(self.tr("Address descriptor"), der_path_e)


class QRAddress(QRCodeWidgetSVG):
def __init__(
self,
) -> None:
super().__init__(clickable=False)
self.setMaximumSize(150, 150)

def set_address(self, bdk_address: bdk.Address):
self.set_data_list([bdk_address.to_qr_uri()])


class AddressDialog(QWidget):
def __init__(
self,
Expand Down Expand Up @@ -83,63 +128,37 @@ def __init__(
self.setLayout(vbox)

upper_widget = QWidget()
upper_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
upper_widget_layout = QHBoxLayout(upper_widget)
upper_widget_layout.setContentsMargins(0, 0, 0, 0)
# upper_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
upper_widget.setLayout(QHBoxLayout())
upper_widget.layout().setContentsMargins(0, 0, 0, 0)

vbox.addWidget(upper_widget)

self.tabs = QTabWidget()
upper_widget_layout.addWidget(self.tabs)

self.tab_details = QWidget()
tab1_layout = QVBoxLayout(self.tab_details)
tab1_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
self.tabs.addTab(self.tab_details, "")
self.tab_advanced = QWidget()
tab2_layout = QVBoxLayout(self.tab_advanced)
tab2_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
self.tabs.addTab(self.tab_advanced, "")

address_info_min = self.wallet.get_address_info_min(address)
if address_info_min:

address_title = (
self.tr("Receiving address of wallet '{wallet_id}' (with index {index})")
if address_info_min.keychain == bdk.KeychainKind.EXTERNAL
else self.tr("Change address of wallet '{wallet_id}' (with index {index})")
).format(wallet_id=wallet.id, index=address_info_min.index)
tab1_layout.addWidget(QLabel(self.tr(address_title) + ":"))
self.addr_e = ButtonEdit(self.address)
self.addr_e.setReadOnly(True)
self.addr_e.add_copy_button()
# self.addr_e.setStyleSheet(f"background-color: {ColorScheme.GREEN.as_color(True).name()};")
tab1_layout.addWidget(self.addr_e)
self.recipient_tabs = RecipientTabWidget(
network=wallet.network,
allow_edit=False,
parent=self,
signals=self.signals,
tab_string=self.tr('Address of wallet "{id}"'),
dismiss_label_on_focus_loss=True,
)
self.recipient_tabs.address = self.address
label = wallet.labels.get_label(self.address)
self.recipient_tabs.label = label if label else ""
self.recipient_tabs.amount = wallet.get_addr_balance(self.address).total

try:
script_pubkey = serialized_to_hex(self.bdk_address.script_pubkey().to_bytes())
except BaseException:
script_pubkey = None
if script_pubkey:
tab2_layout.addWidget(QLabel(self.tr("Script Pubkey") + ":"))
pubkey_e = ButtonEdit(script_pubkey)
pubkey_e.add_copy_button()
pubkey_e.setReadOnly(True)
tab2_layout.addWidget(pubkey_e)
upper_widget.layout().addWidget(self.recipient_tabs)

address_path_str = self.wallet.get_address_path_str(address)
if address_path_str:
tab2_layout.addWidget(QLabel(self.tr("Address descriptor") + ":"))
der_path_e = ButtonEdit(address_path_str, input_field=QTextEdit())
der_path_e.add_copy_button()
der_path_e.setFixedHeight(50)
der_path_e.setReadOnly(True)
tab2_layout.addWidget(der_path_e)
self.tab_advanced = AddressDetailsAdvanced(
bdk_address=self.bdk_address,
address_path_str=self.wallet.get_address_path_str(address),
parent=self,
)
self.recipient_tabs.addTab(self.tab_advanced, "")

self.qr_code = QRCodeWidgetSVG()
self.qr_code.set_data_list([self.bdk_address.to_qr_uri()])
self.qr_code.setMaximumWidth(150)
upper_widget_layout.addWidget(self.qr_code)
self.qr_code = QRAddress()
self.qr_code.set_address(self.bdk_address)
upper_widget.layout().addWidget(self.qr_code)

self.hist_list = HistList(
self.fx,
Expand All @@ -154,12 +173,18 @@ def __init__(
address_domain=[self.address],
column_widths={HistList.Columns.TXID: 100},
)
toolbar = HistListWithToolbar(self.hist_list, self.config, parent=self)
vbox.addWidget(toolbar)
vbox.addWidget(self.hist_list)

vbox.addLayout(Buttons(CloseButton(self)))
self.setupUi()

# Override keyPressEvent method
def keyPressEvent(self, event: QKeyEvent) -> None:
# Check if the pressed key is 'Esc'
if event.key() == Qt.Key.Key_Escape:
# Close the widget
self.close()

def setupUi(self) -> None:
self.tabs.setTabText(self.tabs.indexOf(self.tab_details), self.tr("Details"))
self.tabs.setTabText(self.tabs.indexOf(self.tab_advanced), self.tr("Advanced"))
self.recipient_tabs.updateUi()
self.recipient_tabs.setTabText(self.recipient_tabs.indexOf(self.tab_advanced), self.tr("Advanced"))
Loading

0 comments on commit f766f69

Please sign in to comment.