Revert the v0.3.1 double-invalidation change (it caused an inheritance-list regression: stale/invalidated wills lingered and heir/date updates became incoherent) and add several targeted missed-update fixes plus a UI refinement. Revert (v0.3.1 -> v0.3.2): - Remove Will.mark_invalidated_by_tx() and its call in loop_broadcast_invalidating. core/will.py and gui/qt/dialogs.py are restored to the working v0.3.0 behaviour. The postpone double-invalidation issue is intentionally left open, to be addressed without touching the shared broadcast path. FIX 1 - detect heir removal on Check / Electrum close: - core/will.py (check_willexecutors_and_heirs): the else-branch now raises HeirNotFoundException when a will still carries an heir that is no longer in the current heirs set (heir removed), mirroring the existing 'heir added' path. Rebuild therefore triggers on Check and on_close (same build_will_task path), as decided by the user (manual update only, no auto-rebuild). FIX 2 - Check queries servers for already-sent wills: - core/will.py: new Will.needs_server_check(w) returns True for any VALID will with a will-executor that is not yet CHECKED (no longer limited to PUSHED). - gui/qt/lists.py (PreviewList.check): use needs_server_check so wills stuck on 'New / Not sent' are re-checked instead of reporting 'nothing to do'. FIX 3 - Settings-dialog hide toggles refresh the list: - core/plugin_base.py: new sync_hide_filters() re-reads the cached _hide_invalidated / _hide_replaced flags from the persisted config. - gui/qt/window.py (update_all): call sync_hide_filters() before refreshing, so toggling 'Hide Invalidated' / 'Hide Replaced' in the Settings dialog (which writes the config directly) updates the transaction list immediately instead of requiring an Electrum restart. UI - bold results in the Building Will dialog: - gui/qt/dialogs.py (BalBuildWillDialog): render the right-side results in bold (Ok, Ko, Nothing to do, Skipped, Wait, Timeout, ...) keeping the left-side state labels in normal weight. Centralised in msg_ok/msg_error/msg_warning/ msg_set_status, plus the will-executor push/check rows now show Ok/Ko and True/False in bold + colour (green/red). Tests/tooling: - tests/test_core_will.py: add test_check_heirs_unchanged_is_coherent, test_check_heir_removed_triggers_rebuild, test_check_heir_added_triggers_rebuild, test_needs_server_check. - tests/sim_update_flows.py: real-world update-scenario simulation. - tests/preview_build_will_dialog.py, tests/preview_we_rows.py: GUI-only before/after previews of the bold formatting. - Bump version to 0.3.2 (VERSION, manifest.json, __init__.py, plugin_base.py). 186 tests pass; smoke test, external-zip test and update-flow simulation OK; ruff reports only pre-existing star-import false positives.
111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Render a visual PREVIEW (before/after) of the "Building Will" dialog text.
|
|
|
|
This is a throwaway, GUI-only helper used to show the user how the proposed
|
|
"bold results" formatting looks compared to the current rendering, BEFORE any
|
|
production code is changed. It does NOT import the plugin; it just reproduces
|
|
the exact rich-text the dialog builds via ``msg_set_status`` / ``msg_ok`` /
|
|
``msg_error`` so the preview is faithful.
|
|
|
|
Run:
|
|
QT_QPA_PLATFORM=offscreen python3 tests/preview_build_will_dialog.py
|
|
It writes two PNGs in the repo root: preview_before.png and preview_after.png.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
|
|
|
from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout
|
|
from PyQt6.QtCore import Qt
|
|
|
|
# Same colors as BalBuildWillDialog
|
|
COLOR_WARNING = "#cfa808"
|
|
COLOR_ERROR = "#ff0000"
|
|
COLOR_OK = "#05ad05"
|
|
|
|
|
|
# ---- current rendering (BEFORE) -------------------------------------------
|
|
def ok_before(e="Ok"):
|
|
return "<font color='{}'>{}</font>".format(COLOR_OK, e)
|
|
|
|
|
|
def error_before(e):
|
|
return "<font color='{}'>{}</font>".format(COLOR_ERROR, e)
|
|
|
|
|
|
def row_before(msg, status, color=None):
|
|
if color is None:
|
|
return f"{msg}:\t{status}"
|
|
return "<font color={}>{}:\t{}</font>".format(color, msg, status)
|
|
|
|
|
|
# ---- proposed rendering (AFTER): results in bold --------------------------
|
|
def ok_after(e="Ok"):
|
|
return "<font color='{}'><b>{}</b></font>".format(COLOR_OK, e)
|
|
|
|
|
|
def error_after(e):
|
|
return "<font color='{}'><b>{}</b></font>".format(COLOR_ERROR, e)
|
|
|
|
|
|
def row_after(msg, status, color=None):
|
|
# Left state label stays normal; only the result (status) becomes bold.
|
|
if color is None:
|
|
return f"{msg}:\t<b>{status}</b>"
|
|
# When a color is given for the whole line, keep the label normal and bold
|
|
# only the status portion.
|
|
return "{}:\t<font color={}><b>{}</b></font>".format(msg, color, status)
|
|
|
|
|
|
def build_rows(mode):
|
|
if mode == "before":
|
|
ok, err, row = ok_before, error_before, row_before
|
|
else:
|
|
ok, err, row = ok_after, error_after, row_after
|
|
rows = [
|
|
row("checking variables", "Wait"),
|
|
row("Checking your will", ok()),
|
|
row("Signing your will", "Nothing to do"),
|
|
row("Broadcasting your will to executors", "Nothing to do"),
|
|
ok(),
|
|
row("Invalidating old will", err("Ko")),
|
|
"https://executor.example.org : " + ok(),
|
|
"https://other.example.org : " + err("Ko"),
|
|
"Please wait 2secs",
|
|
row("Will-Executor excluded", "Skipped", COLOR_ERROR),
|
|
]
|
|
return rows
|
|
|
|
|
|
def render(mode, path):
|
|
rows = build_rows(mode)
|
|
full_text = "<br><br>".join(rows).replace("\n", "<br>")
|
|
w = QWidget()
|
|
w.setStyleSheet("background:#2b2b2b;")
|
|
lay = QVBoxLayout(w)
|
|
title = QLabel(f"Building Will — {mode.upper()}")
|
|
title.setStyleSheet("color:#ffffff; font-size:15px; font-weight:bold;")
|
|
lbl = QLabel(full_text)
|
|
lbl.setTextFormat(Qt.TextFormat.RichText)
|
|
lbl.setStyleSheet("color:#dddddd; font-size:13px;")
|
|
lbl_font = lbl.font()
|
|
lbl_font.setPointSize(11)
|
|
lbl.setFont(lbl_font)
|
|
lay.addWidget(title)
|
|
lay.addWidget(lbl)
|
|
w.resize(560, 420)
|
|
w.show()
|
|
app.processEvents()
|
|
pix = w.grab()
|
|
pix.save(path)
|
|
print(f"[{mode}] saved -> {path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = QApplication(sys.argv)
|
|
here = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
render("before", os.path.join(here, "preview_before.png"))
|
|
render("after", os.path.join(here, "preview_after.png"))
|