~zanneth/Octahedron

5188db1c9e50c2931efa128772103d974af4757b — James Magahern 1 year, 4 months ago 96168a3 master
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.
1 files changed, 25 insertions(+), 22 deletions(-)

M gtk/src/create_debt_request_dialog.rs
M gtk/src/create_debt_request_dialog.rs => gtk/src/create_debt_request_dialog.rs +25 -22
@@ 21,13 21,14 @@ enum InternalMessage {
}

pub struct CreateDebtRequestDialog {
    tx:                 Sender<Message>,
    dialog:             gtk::Dialog,
    amount_entry:       gtk::Entry,
    description_entry:  gtk::Entry,
    ok_button:          gtk::Button,
    divide_button:      gtk::ToggleButton,
    editing_locked:     bool,
    tx:                       Sender<Message>,
    dialog:                   gtk::Dialog,
    amount_entry:             gtk::Entry,
    description_entry:        gtk::Entry,
    ok_button:                gtk::Button,
    divide_button:            gtk::ToggleButton,
    divide_button_handler_id: Option<glib::SignalHandlerId>,
    divided_amount:           Option<String>,
}

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 {