From 5188db1c9e50c2931efa128772103d974af4757b Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 15 May 2023 22:53:55 -0700 Subject: [PATCH] CreateDebtRequestDialog: Fix issue with divide button getting into bad state Surprisingly difficult to tell the difference between a user invoked button click/entry change and programmatic change. Block the clicked signal while we're resetting the divide button state to avoid re-entrancy with the clicked signal. v2: Change Optional unwrap to more idiomatic Rust way. --- gtk/src/create_debt_request_dialog.rs | 47 ++++++++++++++------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/gtk/src/create_debt_request_dialog.rs b/gtk/src/create_debt_request_dialog.rs index 37dd377..046d830 100644 --- a/gtk/src/create_debt_request_dialog.rs +++ b/gtk/src/create_debt_request_dialog.rs @@ -21,13 +21,14 @@ enum InternalMessage { } pub struct CreateDebtRequestDialog { - tx: Sender, - dialog: gtk::Dialog, - amount_entry: gtk::Entry, - description_entry: gtk::Entry, - ok_button: gtk::Button, - divide_button: gtk::ToggleButton, - editing_locked: bool, + tx: Sender, + dialog: gtk::Dialog, + amount_entry: gtk::Entry, + description_entry: gtk::Entry, + ok_button: gtk::Button, + divide_button: gtk::ToggleButton, + divide_button_handler_id: Option, + divided_amount: Option, } impl CreateDebtRequestDialog { @@ -49,7 +50,8 @@ impl CreateDebtRequestDialog { description_entry, ok_button, divide_button, - editing_locked: false, + divide_button_handler_id: None, + divided_amount: None, } } @@ -69,10 +71,12 @@ impl CreateDebtRequestDialog { dispatch_msg!(tx, InternalMessage::EntryChanged); })); - self.divide_button.connect_clicked(clone!(@strong tx => move |_| { + let divide_handler_id = self.divide_button.connect_clicked(clone!(@strong tx => move |_| { dispatch_msg!(tx, InternalMessage::DividedAmount); })); + self.divide_button_handler_id = Some(divide_handler_id); + self.reload_button_states(); spawn_local(async move { @@ -132,11 +136,6 @@ impl CreateDebtRequestDialog { } fn apply_divided_amount(&mut self) { - if self.editing_locked { - self.editing_locked = false; - return - } - let mut amount = self.get_amount(); if !self.divide_button.is_active() { // If divide button is pressed already, undo division. @@ -146,12 +145,9 @@ impl CreateDebtRequestDialog { amount = amount / 2; } - // There's no way to tell the difference between user input and programmatic input, so we need - // to use editing_locked here to be able to tell the difference. - self.editing_locked = true; - let divided_amount_str = format!("{:.2}", amount.low_u64() as f64 / 100.0); self.amount_entry.set_text(divided_amount_str.as_str()); + self.divided_amount = Some(self.amount_entry.text().to_string()); } fn reset_divide_button(&mut self) { @@ -159,13 +155,20 @@ impl CreateDebtRequestDialog { return } - if self.editing_locked { - self.editing_locked = false; + let amount_str = self.amount_entry.text(); + if self.divided_amount.as_ref().map_or(false, |s| s.as_str() == amount_str) { + // Don't do anything if the amount hasn't changed since the last time the button was pressed. return } - self.editing_locked = true; - self.divide_button.set_active(false); + // We need to temporarily block the signal handler, otherwise our call to set_active will + // trigger the handler for clicked, which will undo our changes. + let button_handler = self.divide_button_handler_id.as_ref().unwrap(); + self.divide_button.block_signal(button_handler); + { + self.divide_button.set_active(false); + } + self.divide_button.unblock_signal(button_handler); } fn input_state_valid(&self) -> bool { -- 2.45.2