non_blocking_async/
non_blocking_async.rs

1use std::time::Duration;
2
3use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
4use relm4::{Component, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt};
5
6struct App {
7    counter: u8,
8}
9
10#[derive(Debug)]
11enum Msg {
12    Increment,
13    Decrement,
14}
15
16#[relm4::component]
17impl Component for App {
18    type Init = ();
19    type Input = ();
20    type Output = ();
21    type CommandOutput = Msg;
22
23    view! {
24        gtk::Window {
25            set_title: Some("Async Counter"),
26            set_default_size: (300, 100),
27
28            gtk::Box {
29                set_orientation: gtk::Orientation::Vertical,
30                set_margin_all: 5,
31                set_spacing: 5,
32
33                gtk::Button {
34                    set_label: "Increment",
35                    // Messages are fully async, no blocking!
36                    connect_clicked[sender] => move |_| {
37                        sender.oneshot_command(async move {
38                            tokio::time::sleep(Duration::from_secs(1)).await;
39                            Msg::Increment
40                        })
41                    },
42                },
43
44                gtk::Button::with_label("Decrement") {
45                    connect_clicked[sender] => move |_| {
46                        sender.oneshot_command(async move {
47                            tokio::time::sleep(Duration::from_secs(1)).await;
48                            Msg::Decrement
49                        })
50                    },
51                },
52
53                gtk::Label {
54                    set_margin_all: 5,
55                    #[watch]
56                    set_label: &format!("Counter: {}", model.counter),
57                },
58            },
59        }
60    }
61
62    fn init(
63        _: Self::Init,
64        root: Self::Root,
65        sender: ComponentSender<Self>,
66    ) -> ComponentParts<Self> {
67        let model = App { counter: 0 };
68
69        let widgets = view_output!();
70
71        ComponentParts { model, widgets }
72    }
73
74    fn update_cmd(
75        &mut self,
76        msg: Self::CommandOutput,
77        _sender: ComponentSender<Self>,
78        _root: &Self::Root,
79    ) {
80        match msg {
81            Msg::Increment => {
82                self.counter = self.counter.wrapping_add(1);
83            }
84            Msg::Decrement => {
85                self.counter = self.counter.wrapping_sub(1);
86            }
87        }
88    }
89}
90
91fn main() {
92    let app = RelmApp::new("relm4.example.non_blocking_async");
93    app.run::<App>(());
94}