diff --git a/VERSION b/VERSION
index a45be46..1866a36 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.8
+0.2.9
diff --git a/manifest.json b/manifest.json
index 5edff73..e41dec4 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,7 +1,7 @@
{
"name": "BAL",
"fullname": "Bitcoin After Life",
- "description": "Provides free and decentralized inheritance support
Version: 0.2.7",
+ "description": "Provides free and decentralized inheritance support
Version: 0.2.9",
"author":"Svatantrya",
"available_for": ["qt"],
"icon":"icons/bal32x32.png"
diff --git a/qt.py b/qt.py
index 86e1b35..2f5fb0b 100644
--- a/qt.py
+++ b/qt.py
@@ -390,6 +390,26 @@ class shown_cv:
class BalWindow(Logger):
+ """Main application window for Bitcoin After Life inheritance management.
+
+ This class provides the primary UI for:
+ - Managing inheritance plans
+ - Building Wills
+ - Handling heir configurations
+ - Network operations
+ - Transaction signing and broadcasting
+
+ Attributes:
+ bal_plugin (BalPlugin): Reference to the plugin instance
+ config (dict): Application configuration
+ network (Network): Network interface
+ wallet (Abstract_Wallet): Wallet interface
+ heirs (list): List of heir configurations
+ will (Will): Current Will being managed
+ building_will (bool): Flag indicating Will construction in progress
+ stop_build (bool): Flag to stop Will construction
+ """
+
def __init__(self, bal_plugin: "BalPlugin", window: "ElectrumWindow"):
Logger.__init__(self)
self.bal_plugin = bal_plugin
@@ -2069,6 +2089,18 @@ class BalBuildWillDialog(BalDialog):
COLOR_OK = "#05ad05"
def __init__(self, bal_window, parent=None):
+ """Initialize the Build Will dialog.
+
+ Args:
+ bal_window (BalWindow): The main application window
+ parent (QWidget, optional): Parent widget. Defaults to None.
+
+ Initializes:
+ - Main UI components (message label, container widget)
+ - Message queue system with debounce timer
+ - Layout management
+ - Network connection
+ """
if not parent:
parent = bal_window.window
BalDialog.__init__(self, parent, bal_window.bal_plugin, _("Building Will"))
@@ -2076,16 +2108,43 @@ class BalBuildWillDialog(BalDialog):
self.updatemessage.connect(self.msg_update)
self.bal_window = bal_window
self.bal_plugin = bal_window.bal_plugin
+
+ # Main message label
self.message_label = QLabel(_("Building Will:"))
self.vbox = QVBoxLayout(self)
- self.vbox.addWidget(self.message_label,0)
+ self.vbox.addWidget(self.message_label, 0)
+
+ # Container for dynamic messages
self.qwidget = QWidget(self)
- self.vbox.addWidget(self.qwidget,1)
- self.labelsbox=QVBoxLayout(self.qwidget)
+ self.vbox.addWidget(self.qwidget, 1)
+
+ # Layout for messages with reduced spacing
+ self.labelsbox = QVBoxLayout(self.qwidget)
+ self.labelsbox.setContentsMargins(0, 0, 0, 0)
+ self.labelsbox.setSpacing(4) # Reduced spacing between messages
+
+ # Set minimum dimensions
self.setMinimumWidth(600)
self.setMinimumHeight(100)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
- self.labels = []
+
+ # Message queue implementation for efficient updates
+ self._message_queue = [] # Thread-safe message queue
+ self._message_timer = QTimer(self)
+ self._message_timer.setSingleShot(True)
+ self._message_timer.setInterval(50) # Debounce interval: 50ms
+ self._message_timer.timeout.connect(self._process_message_queue)
+
+ # Other initialization
+ self.labels = [] # Immediate message storage
+ self.check_row = None
+ self.inval_row = None
+ self.build_row = None
+ self.sign_row = None
+ self.push_row = None
+ self.network = Network.get_instance()
+ self._stopping = False
+
self.check_row = None
self.inval_row = None
self.build_row = None
@@ -2535,13 +2594,73 @@ class BalBuildWillDialog(BalDialog):
w.deleteLater()
def msg_update(self):
+ """Updates the UI with new messages using a debounced queue system.
+
+ This method implements the following logic:
+ 1. Adds all pending messages to the queue
+ 2. Clears the immediate message storage
+ 3. Starts the debounce timer if not already active
+
+ The actual UI update happens in _process_message_queue after the
+ debounce interval to prevent excessive UI updates.
+
+ Note:
+ Thread-safe operation - can be called from any thread
+ """
+ self._message_queue.extend(self.labels)
+ self.labels = [] # Clear immediate labels after queuing
+ if not self._message_timer.isActive():
+ self._message_timer.start()
+
+ def _process_message_queue(self):
+ """Processes queued messages with debounce for efficient UI updates.
+
+ This method:
+ 1. Clears the existing layout
+ 2. Processes all queued messages
+ 3. Updates the UI once with all new messages
+ 4. Resets the queue
+ 5. Adjusts dialog height based on content
+
+ The debounce interval (50ms) ensures rapid message bursts are
+ processed in a single batch, reducing UI flicker.
+
+ Note:
+ Called automatically by QTimer after debounce interval
+ """
+ if not self._message_queue:
+ return
+
+ # Clear existing layout
self.clear_layout(self.labelsbox)
- for label in self.labels:
- label=label.replace("\n","
")
- qlabel=QLabel(label)
- self.labelsbox.addWidget(QLabel(label),1)
- self.setMinimumHeight(30*(len(self.labels)+2))
-
+
+ # Process all queued messages
+ for text in self._message_queue:
+ try:
+ # Format text for rich display
+ formatted_text = text.replace("\n", "
")
+
+ # Create label with proper settings
+ label = QLabel(formatted_text)
+ label.setWordWrap(True)
+ label.setTextFormat(Qt.TextFormat.RichText)
+ label.setOpenExternalLinks(False) # Security
+
+ # Set size policy
+ label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
+
+ # Add to layout
+ self.labelsbox.addWidget(label)
+
+ except Exception as e:
+ # Log errors without interrupting processing
+ import logging
+ logging.error(f"Error creating label in BalBuildWillDialog: {e}")
+
+ # Reset queue and update dimensions
+ self._message_queue = []
+ self.setMinimumHeight(min(30 * (len(self.labels) + 2), 400)) # Max height limit
+
def get_text(self):
return self.message_label.text()
@@ -3759,4 +3878,20 @@ class CheckAliveException(Exception):
def __init__(self,timestamp_to_check):
self.timestamp_to_check = timestamp_to_check
def __str__(self):
+
+ def __del__(self):
+ """Explicit cleanup to prevent memory leaks.
+
+ This destructor ensures proper cleanup of:
+ - Message queue timer
+ - All widgets in the layout
+ - Network connections
+
+ Called automatically when the dialog is destroyed.
+ """
+ if hasattr(self, '_message_timer') and self._message_timer:
+ self._message_timer.stop()
+ self._message_timer.deleteLater()
+ self.clear_layout(self.labelsbox)
+
return "Check alive expired please update it: {}".format(datetime.fromtimestamp(self.timestamp_to_check).isoformat())