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.
This commit is contained in:
2026-06-28 23:01:38 -04:00
parent edbb3b32ce
commit dd2e160a17
7 changed files with 87 additions and 12 deletions

View File

@@ -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). - Full test suite: `239 passed` (217 previous + 22 new Group E tests).
**Outcome:** DONE (delivered as a ZIP for user testing before commit). **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).

View File

@@ -1 +1 @@
0.3.4 0.3.6

View File

@@ -34,4 +34,4 @@ The plugin targets Electrum 4.7.2 (the last stable release exposing
``json_db.register_dict``) and PyQt6. ``json_db.register_dict``) and PyQt6.
""" """
__version__ = "0.3.4" __version__ = "0.3.6"

View File

@@ -91,7 +91,7 @@ class BalPlugin(BasePlugin):
""" """
_version = None _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. # Command used to open an .ics calendar file, per operating system.
default_app = { default_app = {

View File

@@ -917,9 +917,19 @@ class BalBuildWillDialog(BalDialog):
_("Invalidate your old will"), parent=self _("Invalidate your old will"), parent=self
) )
if password is False: 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.msg_set_invalidating(_("Aborted"))
self.wait(3) self._add_close_button()
self.close()
return return
self.thread.add( self.thread.add(
partial(self.invalidate_task, password, self.bal_window, tx), partial(self.invalidate_task, password, self.bal_window, tx),

View File

@@ -705,13 +705,15 @@ class WillSettingsWidget(QWidget):
self.apply_editable_dates() self.apply_editable_dates()
def apply_editable_dates(self): 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 Outside the "Build your will" wizard (``read_only=True``) the
delivery-time and check-alive dates are display-only by default. When delivery-time, check-alive dates AND the mining fee are display-only by
the user ticks "Editable dates" in the settings they become editable default. When the user ticks "Editable dates" in the settings, all three
here too. The fee field always stays read-only outside the wizard, fields (locktime, threshold and fee) become editable here too; when it
because C2 only concerns the dates. 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 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 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["locktime"].set_read_only(not editable_dates)
self.widgets["threshold"].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): def create_alarms(self, alarm_start, alarm_end):
"""Build the VALARM reminder blocks for the .ics event (Group D / D1). """Build the VALARM reminder blocks for the .ics event (Group D / D1).

View File

@@ -1,7 +1,7 @@
{ {
"name": "bal", "name": "bal",
"fullname": "Bitcoin After Life", "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.", "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", "author": "Svatantrya",
"licence": "MIT", "licence": "MIT",