feat: add will-executor edit dialog on double-click with sync button (↻)
- WillExecutorListWidget: double-click/Enter opens edit dialog - WillExecutorWidget.add() accepts edit_key param for edit mode: pre-populates URL, Info, Base Fee, Address fields - Sync button (↻) pings executor URL via TaskThread and populates fields; updates executor status in list in edit mode (200/KO) - Loading indicator (⟳) during async ping - QMessageBox with dialog as parent for sync errors - Focus returns to URL field after sync error - 'Add another' button only in add mode, no longer default (OK is default) - Removed Promo Code field - Heir dialog: 'Add another' no longer default (matches new pattern)
This commit is contained in:
@@ -17,7 +17,8 @@ and ``dialogs``.
|
|||||||
from .common import *
|
from .common import *
|
||||||
from .common import _, _logger # underscore names are not re-exported by "import *"
|
from .common import _, _logger # underscore names are not re-exported by "import *"
|
||||||
from .widgets import BalCheckBox, PercAmountEdit, WillSettingsWidget
|
from .widgets import BalCheckBox, PercAmountEdit, WillSettingsWidget
|
||||||
from .dialogs import BalBuildWillDialog
|
from PyQt6.QtWidgets import QMessageBox
|
||||||
|
from .dialogs import BalBuildWillDialog, BalDialog
|
||||||
|
|
||||||
|
|
||||||
class HeirListWidget(MyTreeView, MessageBoxMixin):
|
class HeirListWidget(MyTreeView, MessageBoxMixin):
|
||||||
@@ -759,6 +760,16 @@ class WillExecutorListWidget(MyTreeView):
|
|||||||
self._bal_parent.save_willexecutors()
|
self._bal_parent.save_willexecutors()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def on_activated(self, idx):
|
||||||
|
self.on_double_click(idx)
|
||||||
|
|
||||||
|
def on_double_click(self, idx):
|
||||||
|
edit_key = self.get_edit_key_from_coordinate(
|
||||||
|
idx.row(), self.Columns.URL
|
||||||
|
)
|
||||||
|
if edit_key and edit_key in self._bal_parent.willexecutors_list:
|
||||||
|
self._bal_parent.add(edit_key)
|
||||||
|
|
||||||
def get_edit_key_from_coordinate(self, row, col):
|
def get_edit_key_from_coordinate(self, row, col):
|
||||||
role = self.ROLE_HEIR_KEY + col
|
role = self.ROLE_HEIR_KEY + col
|
||||||
a = self.get_role_data_from_coordinate(row, col, role=role)
|
a = self.get_role_data_from_coordinate(row, col, role=role)
|
||||||
@@ -951,13 +962,200 @@ class WillExecutorWidget(QWidget, MessageBoxMixin):
|
|||||||
vbox.addLayout(buttonbox)
|
vbox.addLayout(buttonbox)
|
||||||
# self.will_executor_list_widget.update()
|
# self.will_executor_list_widget.update()
|
||||||
|
|
||||||
def add(self):
|
def add(self, edit_key=None):
|
||||||
self.willexecutors_list["http://localhost:8080"] = {
|
executor = None
|
||||||
"info": "New Will Executor",
|
if edit_key:
|
||||||
"base_fee": 0,
|
executor = self.willexecutors_list.get(edit_key)
|
||||||
|
title = _("Edit: {}").format(edit_key)
|
||||||
|
else:
|
||||||
|
title = _("New Will Executor")
|
||||||
|
d = BalDialog(
|
||||||
|
self.bal_window.window,
|
||||||
|
self.bal_plugin,
|
||||||
|
self.bal_plugin.get_window_title(title),
|
||||||
|
)
|
||||||
|
|
||||||
|
vbox = QVBoxLayout(d)
|
||||||
|
grid = QGridLayout()
|
||||||
|
|
||||||
|
url_edit = QLineEdit()
|
||||||
|
url_edit.setFixedWidth(32 * char_width_in_lineedit())
|
||||||
|
info_edit = QLineEdit("New Will Executor")
|
||||||
|
info_edit.setFixedWidth(32 * char_width_in_lineedit())
|
||||||
|
base_fee_spin = QSpinBox()
|
||||||
|
base_fee_spin.setRange(0, 1000000)
|
||||||
|
base_fee_spin.setValue(0)
|
||||||
|
address_edit = QLineEdit()
|
||||||
|
address_edit.setFixedWidth(32 * char_width_in_lineedit())
|
||||||
|
sync_btn = QPushButton("\u21BB")
|
||||||
|
sync_btn.setFixedWidth(32)
|
||||||
|
loading_label = QLabel()
|
||||||
|
d._sync_active = False
|
||||||
|
|
||||||
|
if executor:
|
||||||
|
url_edit.setText(edit_key)
|
||||||
|
info_edit.setText(str(executor.get("info", "New Will Executor")))
|
||||||
|
base_fee_spin.setValue(int(executor.get("base_fee", 0)))
|
||||||
|
address_edit.setText(str(executor.get("address", "")))
|
||||||
|
|
||||||
|
def on_sync():
|
||||||
|
url = url_edit.text().strip()
|
||||||
|
if not url:
|
||||||
|
self.show_error(_("URL is required"))
|
||||||
|
return
|
||||||
|
tmp = {}
|
||||||
|
sync_btn.setEnabled(False)
|
||||||
|
loading_label.setText("\u27F3")
|
||||||
|
d._sync_active = True
|
||||||
|
|
||||||
|
def task():
|
||||||
|
return Willexecutors.get_info_task(url, tmp)
|
||||||
|
|
||||||
|
def on_success(result):
|
||||||
|
if not getattr(d, "_sync_active", False):
|
||||||
|
return
|
||||||
|
if result.get("status") == 200:
|
||||||
|
info_edit.setText(str(result.get("info", "")))
|
||||||
|
base_fee_spin.setValue(int(result.get("base_fee", 0)))
|
||||||
|
address_edit.setText(str(result.get("address", "")))
|
||||||
|
if edit_key and edit_key in self.willexecutors_list:
|
||||||
|
self.willexecutors_list[edit_key].update({
|
||||||
|
"status": 200,
|
||||||
|
"info": result.get("info", ""),
|
||||||
|
"base_fee": result.get("base_fee", 0),
|
||||||
|
"address": result.get("address", ""),
|
||||||
|
"last_update": result.get(
|
||||||
|
"last_update", datetime.now().timestamp()
|
||||||
|
),
|
||||||
|
})
|
||||||
|
self.will_executor_list_widget.update()
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(
|
||||||
|
d,
|
||||||
|
_("Error"),
|
||||||
|
_("Could not reach server at {}").format(url),
|
||||||
|
)
|
||||||
|
url_edit.setFocus()
|
||||||
|
url_edit.selectAll()
|
||||||
|
sync_btn.setEnabled(True)
|
||||||
|
loading_label.clear()
|
||||||
|
d._sync_active = False
|
||||||
|
|
||||||
|
def on_error(exc_info):
|
||||||
|
if not getattr(d, "_sync_active", False):
|
||||||
|
return
|
||||||
|
QMessageBox.warning(
|
||||||
|
d,
|
||||||
|
_("Error"),
|
||||||
|
_("Error contacting server: {}").format(
|
||||||
|
str(exc_info[1])
|
||||||
|
),
|
||||||
|
)
|
||||||
|
url_edit.setFocus()
|
||||||
|
url_edit.selectAll()
|
||||||
|
sync_btn.setEnabled(True)
|
||||||
|
loading_label.clear()
|
||||||
|
d._sync_active = False
|
||||||
|
|
||||||
|
def on_done():
|
||||||
|
pass
|
||||||
|
|
||||||
|
sync_thread = TaskThread(d)
|
||||||
|
sync_thread.add(
|
||||||
|
task, on_success=on_success, on_done=on_done, on_error=on_error
|
||||||
|
)
|
||||||
|
|
||||||
|
sync_btn.clicked.connect(on_sync)
|
||||||
|
|
||||||
|
if not edit_key:
|
||||||
|
add_another_btn = QPushButton(_("Add another"))
|
||||||
|
self._add_another = False
|
||||||
|
|
||||||
|
def add_another():
|
||||||
|
self._add_another = True
|
||||||
|
d.accept()
|
||||||
|
|
||||||
|
add_another_btn.clicked.connect(add_another)
|
||||||
|
else:
|
||||||
|
self._add_another = False
|
||||||
|
|
||||||
|
row = 0
|
||||||
|
grid.addWidget(QLabel(_("URL")), row, 0)
|
||||||
|
grid.addWidget(url_edit, row, 1)
|
||||||
|
grid.addWidget(sync_btn, row, 2)
|
||||||
|
grid.addWidget(loading_label, row, 3)
|
||||||
|
grid.addWidget(
|
||||||
|
HelpButton(_("Will executor server URL (e.g. http://192.168.1.100:8080)")),
|
||||||
|
row,
|
||||||
|
4,
|
||||||
|
)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
grid.addWidget(QLabel(_("Info")), row, 0)
|
||||||
|
grid.addWidget(info_edit, row, 1)
|
||||||
|
grid.addWidget(
|
||||||
|
HelpButton(_("A short description or name for this executor")),
|
||||||
|
row,
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
grid.addWidget(QLabel(_("Base Fee (sats)")), row, 0)
|
||||||
|
grid.addWidget(base_fee_spin, row, 1)
|
||||||
|
grid.addWidget(
|
||||||
|
HelpButton(_("Base fee in satoshis")),
|
||||||
|
row,
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
|
||||||
|
row += 1
|
||||||
|
grid.addWidget(QLabel(_("Address")), row, 0)
|
||||||
|
grid.addWidget(address_edit, row, 1)
|
||||||
|
grid.addWidget(
|
||||||
|
HelpButton(_("Bitcoin address for fee payments (optional)")),
|
||||||
|
row,
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
|
||||||
|
vbox.addLayout(grid)
|
||||||
|
buttons = [CancelButton(d), OkButton(d)]
|
||||||
|
if not edit_key:
|
||||||
|
buttons.append(add_another_btn)
|
||||||
|
vbox.addLayout(Buttons(*buttons))
|
||||||
|
|
||||||
|
while d.exec():
|
||||||
|
url = url_edit.text().strip()
|
||||||
|
if not url:
|
||||||
|
self.show_error(_("URL is required"))
|
||||||
|
continue
|
||||||
|
if edit_key:
|
||||||
|
old_url = edit_key
|
||||||
|
ex = self.willexecutors_list[old_url]
|
||||||
|
ex.update({
|
||||||
|
"info": info_edit.text().strip() or "New Will Executor",
|
||||||
|
"base_fee": base_fee_spin.value(),
|
||||||
|
"address": address_edit.text().strip(),
|
||||||
|
})
|
||||||
|
if url != old_url:
|
||||||
|
self.willexecutors_list[url] = ex
|
||||||
|
del self.willexecutors_list[old_url]
|
||||||
|
else:
|
||||||
|
self.willexecutors_list[url] = {
|
||||||
|
"info": info_edit.text().strip() or "New Will Executor",
|
||||||
|
"base_fee": base_fee_spin.value(),
|
||||||
|
"address": address_edit.text().strip(),
|
||||||
|
"selected": False,
|
||||||
"status": "-1",
|
"status": "-1",
|
||||||
}
|
}
|
||||||
self.will_executor_list_widget.update()
|
self.will_executor_list_widget.update()
|
||||||
|
Willexecutors.save(self.bal_window.bal_plugin, self.willexecutors_list)
|
||||||
|
if not self._add_another:
|
||||||
|
break
|
||||||
|
self._add_another = False
|
||||||
|
url_edit.clear()
|
||||||
|
info_edit.setText("New Will Executor")
|
||||||
|
base_fee_spin.setValue(0)
|
||||||
|
address_edit.clear()
|
||||||
|
|
||||||
def download_list(self, wes=None):
|
def download_list(self, wes=None):
|
||||||
# Both this button and the wizard go through the same code path on
|
# Both this button and the wizard go through the same code path on
|
||||||
|
|||||||
@@ -218,7 +218,6 @@ class BalWindow:
|
|||||||
d.accept()
|
d.accept()
|
||||||
|
|
||||||
new_heir_button.clicked.connect(new_heir)
|
new_heir_button.clicked.connect(new_heir)
|
||||||
new_heir_button.setDefault(True)
|
|
||||||
|
|
||||||
grid.addWidget(QLabel(_("Name")), 1, 0)
|
grid.addWidget(QLabel(_("Name")), 1, 0)
|
||||||
grid.addWidget(heir_name, 1, 1)
|
grid.addWidget(heir_name, 1, 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user