v0.5.10: Check Alive/BASIC fixes, UX improvements, Raw-Date handling.

This commit is contained in:
2026-07-05 09:03:57 +00:00
parent 4c81290954
commit 527ae95c75
5 changed files with 229 additions and 88 deletions

View File

@@ -291,18 +291,39 @@ class BalTimeEditWidget(QWidget, _LockTimeEditor):
# combo is hidden. We keep a flag so the rest of __init__ can force the
# Date editor regardless of the stored value's format.
self._basic_mode = self.bal_window.bal_plugin.is_basic_mode()
# Tracks whether the user PICKED an editor by hand from the Raw/Date
# selector (set only on the combo's `activated` signal, i.e. real user
# interaction). It lets the runtime BASIC<->ADVANCED switch respect a
# manual "Date" choice in ADVANCED instead of forcing RAW back. It stays
# False for programmatic changes (defaults, switches).
self._user_picked_editor = False
default_index = 0
if not default_locktime:
default_locktime = self.bal_window.bal_plugin.WILL_SETTINGS.get()[self.base_field]
try:
int(default_locktime)
default_index = 1
except Exception:
default_index = 0
# Force the calendar ("Date") editor in BASIC mode so the user always
# picks a date and never sees the RAW input ("30d"/"1y" style).
# Default editor per mode (owner request):
# * BASIC -> Date editor (index 1); the Raw/Date selector is hidden,
# so the user always picks a date and never sees RAW.
# * ADVANCED -> RAW editor (index 0) by default; the selector stays
# visible so the user can switch to Date manually.
if self._basic_mode:
default_index = 1
else:
default_index = 0
# In ADVANCED we default to RAW. If the stored value is an absolute
# timestamp (a bare number), showing it in RAW would display that
# raw number; substitute the relative default ("1y"/"30d") so the
# RAW editor opens with a human-readable duration instead.
try:
int(default_locktime)
is_absolute = True
except Exception:
is_absolute = False
if is_absolute:
default_locktime = (
self.bal_window.bal_plugin.default_will_settings_relative()[
self.base_field
]
)
#hbox.addWidget(QLabel(self.label_text))
help_button=HelpButton(self.help_text)
help_button.setText(self.label_text)
@@ -316,6 +337,11 @@ class BalTimeEditWidget(QWidget, _LockTimeEditor):
# align all rows on a common left edge (see its vertical layout).
self.prefix_widget = help_button
self.combo.currentIndexChanged.connect(self.on_current_index_changed)
# `activated` fires ONLY on real user interaction with the selector (not
# on programmatic setCurrentIndex), so we use it to remember that the
# user picked the editor by hand. This is what lets the runtime
# BASIC<->ADVANCED switch respect a manual "Date" choice in ADVANCED.
self.combo.activated.connect(self._on_user_picked_editor)
for w in self.editors:
w.setVisible(False)
@@ -360,6 +386,16 @@ class BalTimeEditWidget(QWidget, _LockTimeEditor):
update_heirs_dialog,
)
def _on_user_picked_editor(self, i):
"""Record that the user chose the Raw/Date editor by hand.
Connected to the combo's ``activated`` signal, which only fires on real
user interaction (not on programmatic ``setCurrentIndex``). Used by the
runtime BASIC<->ADVANCED switch to respect a manual "Date" choice in
ADVANCED instead of forcing RAW back.
"""
self._user_picked_editor = True
def on_current_index_changed(self, i):
self.current_index = i
for w in self.editors:
@@ -408,9 +444,11 @@ class BalTimeEditWidget(QWidget, _LockTimeEditor):
(owner request: keep the current value to avoid confusing the delivery
date with the inheritance). It is called from
``WillSettingsWidget.apply_user_type_visibility()`` (triggered by
``BalWindow.update_all()`` on a BASIC<->ADVANCED switch), so toggling the
mode takes effect immediately on the already-existing WILL/HEIR toolbars
without restarting Electrum.
``BalWindow.update_all()``, which also runs on every CHECK/refresh), so
it must be side-effect free on the editor - otherwise pressing CHECK
would reset a manual Date/RAW choice back to the default. The actual
per-mode editor default lives in ``apply_user_type_editor_default()``,
which is called ONLY on a real USER TYPE change.
It is safe to call repeatedly and on either layout (horizontal toolbar or
vertical wizard): it only flips the visibility of the Raw/Date combo.
@@ -421,10 +459,37 @@ class BalTimeEditWidget(QWidget, _LockTimeEditor):
# If the mode cannot be read, show the combo (the safe, most
# capable default for an existing widget).
basic = False
# Hidden in BASIC, visible in ADVANCED. The current value/editor is left
# untouched on purpose (see the docstring).
self.combo.setVisible(not basic)
def apply_user_type_editor_default(self):
"""Set the ACTIVE Raw/Date editor to the per-mode default.
Split out from ``apply_user_type_visibility`` (Opzione 2) so it runs
ONLY on a real BASIC<->ADVANCED USER TYPE change, not on every
``update_all()``/CHECK refresh. That is what stopped pressing CHECK from
resetting a manual Date choice back to RAW.
Behaviour:
* BASIC -> always the Date editor (index 1); the selector is hidden,
so the field must not stay on RAW.
* ADVANCED -> RAW by default (index 0), UNLESS the user previously
picked an editor by hand (``_user_picked_editor``), in
which case their choice is left untouched.
"""
try:
basic = self.bal_window.bal_plugin.is_basic_mode()
except Exception:
basic = False
try:
if basic:
self.set_index(1)
else:
if not self._user_picked_editor:
self.set_index(0)
except Exception:
# Never let a cosmetic editor switch break mode toggling.
pass
def set_value(
self,
x: Any,
@@ -653,6 +718,8 @@ class ThresholdTimeWidget(BalTimeEditWidget):
"if you choose Raw, you can insert various options based on suffix:<br>"
" - d: number of days after current day(ex: 1d means tomorrow)<br>"
" - y: number of years after current day(ex: 1y means one year from today)<br>"
"<br><b>Note:</b> the date/time is expressed in your computer's "
"<b>Local time</b> (not UTC time).<br>"
)
label_text = "🚨"
#label_text = "Check Alive"
@@ -682,6 +749,8 @@ class LockTimeWidget(BalTimeEditWidget):
"if you choose Raw, you can insert various options based on suffix:<br>"
" - d: number of days after current day(ex: 1d means tomorrow)<br>"
" - y: number of years after currrent day(ex: 1y means one year from today)<br>"
"<br><b>Note:</b> the date/time is expressed in your computer's "
"<b>Local time</b> (not UTC time).<br>"
)
label_text = "🚛"
#label_text = "Locktime"
@@ -711,6 +780,12 @@ class WillSettingsWidget(QWidget):
# alive and fee fields are display-only; they can only be edited from
# the "Build your will" wizard, which passes read_only=False.
self.read_only = read_only
# Remember which layout this widget was built with, so the per-update
# hooks (apply_editable_dates / apply_user_type_visibility) can tell the
# main-window toolbar ("h") apart from the wizard (vertical) - needed
# for the BASIC-mode Check-Alive "visible but read-only in the main
# window only" behaviour.
self.layout_type = layout_type
box = QHBoxLayout(self) if layout_type == "h" else QVBoxLayout(self)
self.calendar_button = BalCalendarButton(self.bal_window, self._ics_provider)
@@ -726,13 +801,13 @@ class WillSettingsWidget(QWidget):
self.widgets["threshold"] = ThresholdTimeWidget(bal_window, self)
self.widgets["locktime"].valueEdited.connect(self.on_locktime_change)
self.widgets["threshold"].valueEdited.connect(self.on_locktime_change)
# SIMPLE / ADVANCED: in BASIC mode hide the whole "Check Alive"
# (threshold) row, including its leading icon. The widget is still
# created and kept in self.widgets so the rest of the code (and the
# saved settings) keep working; it is only hidden from view. The
# Delivery time (locktime) row stays visible. We hide it after creation
# so both the horizontal (toolbar/Heirs) and vertical (wizard) layouts
# below add an already-hidden widget.
# SIMPLE / ADVANCED: in BASIC mode the "Check Alive" (threshold) row is
# hidden EVERYWHERE (both the main-window toolbar and the wizard). The
# user must never see or touch the Check Alive in BASIC. The widget is
# still created and kept in self.widgets so the rest of the code and the
# saved settings keep working; it is only hidden from view. (This
# reverts the v0.5.2 experiment that had shown it read-only in the main
# window - owner asked to hide it again.)
if bal_window.bal_plugin.is_basic_mode():
self.widgets["threshold"].setVisible(False)
# self.widgets['baltx_fees'].valueChange.connect(self.bal_window.update_setting_widgets)
@@ -954,7 +1029,9 @@ class WillSettingsWidget(QWidget):
basic = False
threshold = self.widgets.get("threshold")
if threshold is not None:
# Hidden in BASIC, visible in ADVANCED.
# Hidden in BASIC, visible in ADVANCED - in BOTH layouts (main
# window toolbar and wizard). Reverts the v0.5.2 experiment that
# kept it visible in the main window in BASIC.
threshold.setVisible(not basic)
# Task #04: also re-apply the Raw/Date selector visibility on BOTH the
@@ -969,6 +1046,19 @@ class WillSettingsWidget(QWidget):
if callable(apply_combo):
apply_combo()
def apply_user_type_editor_default(self):
"""Apply the per-mode Raw/Date editor default to both time fields.
Called ONLY on a real BASIC<->ADVANCED USER TYPE change (not on every
refresh/CHECK), so a manual Date/RAW choice is preserved when the user
just presses CHECK. See BalTimeEditWidget.apply_user_type_editor_default.
"""
for field in ("locktime", "threshold"):
widget = self.widgets.get(field)
apply_default = getattr(widget, "apply_user_type_editor_default", None)
if callable(apply_default):
apply_default()
def open_or_save_calendar(self):
"""Build and save an .ics calendar file with SEPARATE reminder events.
@@ -1248,6 +1338,43 @@ class WillSettingsWidget(QWidget):
except Exception as _e:
pass
# VISUAL WARNING (ToDo #5): the Check Alive must always be EARLIER than
# the delivery time. If the user sets a Check Alive that is later than
# (or equal to) the delivery time, tint its box with a soft red so the
# problem is obvious immediately, instead of only surfacing later as a
# build error. Applied only in ADVANCED mode (in BASIC the Check Alive
# is hidden and not editable, so there is nothing to warn about). The
# tint is cleared again as soon as the relationship becomes valid.
try:
SOFT_RED = "#FCE4E4"
threshold_box = self.widgets["threshold"]
if not self.bal_window.bal_plugin.is_basic_mode():
if threshold.to_timestamp() >= locktime.to_timestamp():
# Only set a background colour, and DO NOT touch the border:
# styling the border of a QDateTimeEdit/QAbstractSpinBox via
# stylesheet makes Qt stop drawing its native up/down spin
# arrows. Scoping the rule to the inner editor widget types
# (rather than the whole container) keeps the tint on the
# value box while leaving the arrows intact.
threshold_box.setStyleSheet(
"QDateTimeEdit, QLineEdit, QAbstractSpinBox "
"{ background-color: %s; }" % SOFT_RED
)
threshold_box.setToolTip(
_(
"The Check Alive date must be earlier than the "
"delivery time."
)
)
else:
threshold_box.setStyleSheet("")
threshold_box.setToolTip("")
else:
# BASIC: never show the warning styling (field is hidden).
threshold_box.setStyleSheet("")
except Exception as _e:
pass
class PercAmountEdit(BTCAmountEdit):