gstore 0.10.4

Global and local state management in redux style for applications written in Rust
Documentation
use std::rc::Rc;

use crate::{Actionable, Store};
use gtk::prelude::GtkApplicationExt;
use gtk::{
    gio::SimpleAction,
    glib::MainContext,
    prelude::{ActionExt, ActionMapExt},
};

impl<A, S> Store<A, S>
where
    A: Actionable + Clone + std::fmt::Debug + Send + Sync + 'static,
    S: Clone + std::fmt::Debug + Default + Send + Sync + 'static,
{
    pub fn bind_gtk(
        self: Rc<Self>,
        app: &libadwaita::Application,
        root_reducer: impl Fn(&A, &mut S) + 'static,
    ) {
        // get the store instance
        let store = self;

        // connect store to gtk
        {
            let (s, r) = async_channel::unbounded();
            let reduce = store.init(
                move |a, s| {
                    root_reducer(a, s);
                },
                move |a| {
                    s.send_blocking(a).expect("Failed to send action.");
                },
            );
            MainContext::default().spawn_local(async move {
                loop {
                    match r.recv().await {
                        Ok(a) => reduce(a),
                        Err(e) => {
                            log::error!("gstore recv action lead to error: {e}")
                        }
                    }
                }
            });
        }

        // translate store actions to gtk
        for action in A::list() {
            let name = action.name();
            let ga = SimpleAction::new(name, None);
            ga.set_enabled(true);
            app.add_action(&ga);

            if let Some(keybinding) = action.keybinding() {
                app.set_accels_for_action(&format!("app.{}", name), &[&keybinding.to_gtk()]);
            }

            let s = store.clone();
            ga.connect_activate(move |a, _| {
                if let Some(action) = A::try_from_name(a.name().as_str()) {
                    s.dispatch(action);
                } else {
                    log::error!("Action got lost in translation: {:?}", a);
                }
            });
        }
    }
}

impl crate::Keybinding {
    fn to_gtk(&self) -> String {
        match self {
            crate::Keybinding::Shift(key) => {
                format!("<shift>{}", key)
            }
            crate::Keybinding::Super(key) => {
                format!("<super>{}", key)
            }
            crate::Keybinding::Alt(key) => {
                format!("<alt>{}", key)
            }
            crate::Keybinding::Ctrl(key) => {
                format!("<primary>{}", key)
            }
            crate::Keybinding::Just(key) => key.to_string(),
        }
    }
}