From dd2e160a1790a653f02bed2d534360884db3a497 Mon Sep 17 00:00:00 2001 From: donkey-ai Date: Sun, 28 Jun 2026 23:01:38 -0400 Subject: [PATCH] fix(bal): black bar on cancelled invalidation + editable fee follows dates (v0.3.6) Two GUI fixes bundled together (v0.3.6): - Fix #10 (black bar): in dialogs.py on_success_phase1, the cancelled invalidation branch no longer calls the blocking self.wait(3)+self.close(). wait() uses time.sleep() and runs in the GUI thread, freezing the UI so the 'Building Will' dialog could not repaint the area it just resized, leaving a black rectangle at the bottom. It now shows 'Aborted' plus the existing non-blocking Close button (_add_close_button), consistent with the other end-of-flow branches. - Fix #11 (editable fee): in widgets.py WillSettingsWidget.apply_editable_dates, the fee widget (baltx_fees) now follows the same 'Editable dates' setting as the locktime/threshold widgets (set_read_only(not editable_dates)) instead of being forced read-only. With the setting ticked, dates AND fee are editable outside the wizard; unticked, all three are read-only. Default stays OFF. Version bumped 0.3.5 -> 0.3.6 (manifest.json, __init__.py, plugin_base.py, VERSION). CHANGELOG: entries #10 and #11. ruff clean; full suite 239 passed. --- CHANGELOG.md | 61 +++++++++++++++++++++++++++++++++++++++++ bal/VERSION | 2 +- bal/__init__.py | 2 +- bal/core/plugin_base.py | 2 +- bal/gui/qt/dialogs.py | 14 ++++++++-- bal/gui/qt/widgets.py | 16 +++++++---- bal/manifest.json | 2 +- 7 files changed, 87 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0dff0..3a6385e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -617,3 +617,64 @@ the plugin, all driven by a single self-contained fake wallet named - Full test suite: `239 passed` (217 previous + 22 new Group E tests). **Outcome:** DONE (delivered as a ZIP for user testing before commit). + +## 10. Fix - black bar when cancelling the "invalidate old will" signature + +**Bug:** when the user postpones a will's delivery date and the plugin asks to +invalidate the previous (earlier-locktime) will first, cancelling the signature +prompt left a black/undrawn rectangle at the bottom of the "Building Will" +dialog. + +**Root cause:** in `bal/gui/qt/dialogs.py`, `on_success_phase1` handled the +cancelled-invalidation case with `self.wait(3)` followed by `self.close()`. +`wait()` uses `time.sleep()`, but `on_success_phase1` runs in the GUI thread, so +the sleep froze the interface for several seconds. While frozen, the dialog +could not repaint the area it had just resized, leaving an undrawn (black) +region at the bottom of the window. + +**Fix (Variant A):** +- `bal/gui/qt/dialogs.py` + - In `on_success_phase1`, the cancelled-invalidation branch no longer calls + the blocking `self.wait(3)` + `self.close()`. It now marks the step as + "Aborted" and shows the existing non-blocking "Close" button + (`_add_close_button()`), so the GUI is never blocked and the bottom of the + dialog repaints correctly. The user reads the outcome and dismisses the + dialog when ready, consistent with the other end-of-flow branches. + +**Verification:** +- `py_compile` on the changed file: OK. +- `ruff check`: no new errors (only the pre-existing F401/F403/F405 star-import + noise and an unrelated F841 at line 615). +- Full test suite: `239 passed`. + +**Outcome:** DONE (delivered as a ZIP for user testing before commit). + +## 11. Fee field now follows the "Editable dates" setting + +**Request:** the "Editable dates" checkbox in the plugin settings (added in +Group C / C2) lets the user edit the delivery-time and check-alive dates +outside the wizard. The mining-fee field next to them, however, stayed always +read-only. The user asked for the fee to follow the same rule as the dates. + +**What changed:** +- `bal/gui/qt/widgets.py` + - In `WillSettingsWidget.apply_editable_dates()`, the fee widget + (`baltx_fees`) is now locked/unlocked with `set_read_only(not + editable_dates)`, exactly like the locktime and threshold widgets, instead + of being forced to `set_read_only(True)`. The method docstring was updated + to state that the fee follows the same "Editable dates" rule. + +**Effect:** with "Editable dates" ticked, the delivery time, check-alive date +AND the fee become editable outside the wizard; with it unticked, all three go +back to read-only. Inside the wizard everything stays editable as before. The +change takes effect immediately (the method is already re-run from +`BalWindow.update_all()`), with no need to reopen the window. + +**Verification:** +- `py_compile` on the changed file: OK. +- `ruff check`: no new errors (only pre-existing star-import noise and unrelated + F841 warnings at lines 547 / 792). +- Full test suite: `239 passed`. + +**Outcome:** DONE (delivered together with fix #10 in a single ZIP for user +testing before commit). diff --git a/bal/VERSION b/bal/VERSION index 42045ac..449d7e7 100644 --- a/bal/VERSION +++ b/bal/VERSION @@ -1 +1 @@ -0.3.4 +0.3.6 diff --git a/bal/__init__.py b/bal/__init__.py index b657cf3..d4c71ef 100644 --- a/bal/__init__.py +++ b/bal/__init__.py @@ -34,4 +34,4 @@ The plugin targets Electrum 4.7.2 (the last stable release exposing ``json_db.register_dict``) and PyQt6. """ -__version__ = "0.3.4" +__version__ = "0.3.6" diff --git a/bal/core/plugin_base.py b/bal/core/plugin_base.py index a5b99e3..804ad5b 100644 --- a/bal/core/plugin_base.py +++ b/bal/core/plugin_base.py @@ -91,7 +91,7 @@ class BalPlugin(BasePlugin): """ _version = None - __version__ = "0.3.4" # AUTOMATICALLY GENERATED DO NOT EDIT + __version__ = "0.3.6" # AUTOMATICALLY GENERATED DO NOT EDIT # Command used to open an .ics calendar file, per operating system. default_app = { diff --git a/bal/gui/qt/dialogs.py b/bal/gui/qt/dialogs.py index 7eb9e68..fa62ab3 100644 --- a/bal/gui/qt/dialogs.py +++ b/bal/gui/qt/dialogs.py @@ -917,9 +917,19 @@ class BalBuildWillDialog(BalDialog): _("Invalidate your old will"), parent=self ) if password is False: + # The user cancelled the password prompt for the invalidation. + # We must NOT call self.wait(3) here: on_success_phase1 runs in + # the GUI thread, so wait()'s time.sleep() would freeze the UI + # for several seconds. While frozen the dialog cannot repaint + # the area it just resized, leaving a black, undrawn rectangle + # at the bottom of the "Building Will" window (the reported bug). + # + # Instead, mark the invalidation as "Aborted" and offer a + # non-blocking "Close" button (the same helper used by the + # normal finish path), so the user can read the outcome and + # dismiss the dialog when they want, without blocking the GUI. self.msg_set_invalidating(_("Aborted")) - self.wait(3) - self.close() + self._add_close_button() return self.thread.add( partial(self.invalidate_task, password, self.bal_window, tx), diff --git a/bal/gui/qt/widgets.py b/bal/gui/qt/widgets.py index 2843af7..ba479df 100644 --- a/bal/gui/qt/widgets.py +++ b/bal/gui/qt/widgets.py @@ -705,13 +705,15 @@ class WillSettingsWidget(QWidget): self.apply_editable_dates() def apply_editable_dates(self): - """Re-read the EDITABLE_DATES setting and lock/unlock the date fields. + """Re-read the EDITABLE_DATES setting and lock/unlock the editable fields. Outside the "Build your will" wizard (``read_only=True``) the - delivery-time and check-alive dates are display-only by default. When - the user ticks "Editable dates" in the settings they become editable - here too. The fee field always stays read-only outside the wizard, - because C2 only concerns the dates. + delivery-time, check-alive dates AND the mining fee are display-only by + default. When the user ticks "Editable dates" in the settings, all three + fields (locktime, threshold and fee) become editable here too; when it + is unticked they all go back to read-only. The fee follows exactly the + same rule as the dates (it used to stay always read-only, but the user + asked for the fee to be editable together with the dates). This is safe to call repeatedly: it only adjusts the read-only state of the already-created sub-widgets, it does not rebuild anything. It is the @@ -732,7 +734,9 @@ class WillSettingsWidget(QWidget): self.widgets["locktime"].set_read_only(not editable_dates) self.widgets["threshold"].set_read_only(not editable_dates) - self.widgets["baltx_fees"].set_read_only(True) + # The fee now follows the very same "Editable dates" rule as the dates: + # editable outside the wizard only when the setting is ticked. + self.widgets["baltx_fees"].set_read_only(not editable_dates) def create_alarms(self, alarm_start, alarm_end): """Build the VALARM reminder blocks for the .ics event (Group D / D1). diff --git a/bal/manifest.json b/bal/manifest.json index 4ce9686..923a5f3 100644 --- a/bal/manifest.json +++ b/bal/manifest.json @@ -1,7 +1,7 @@ { "name": "bal", "fullname": "Bitcoin After Life", - "version": "0.3.4", + "version": "0.3.6", "description": "Provides free and decentralized Bitcoin inheritance support. Build time-locked 'will' transactions that transfer funds to your heirs if you stop refreshing them (dead-man's switch), optionally relayed by will-executor servers.", "author": "Svatantrya", "licence": "MIT",