simple_async/
simple_async.rs

1use std::time::Duration;
2
3use gtk::prelude::*;
4use relm4::{
5    RelmApp, RelmWidgetExt,
6    component::{AsyncComponent, AsyncComponentParts, AsyncComponentSender},
7    loading_widgets::LoadingWidgets,
8    view,
9};
10
11struct AppModel {
12    counter: u8,
13}
14
15#[derive(Debug)]
16enum AppMsg {
17    Increment,
18    Decrement,
19}
20
21#[relm4::component(async)]
22impl AsyncComponent for AppModel {
23    type Init = u8;
24    type Input = AppMsg;
25    type Output = ();
26    type CommandOutput = ();
27
28    view! {
29        gtk::Window {
30            gtk::Box {
31                set_orientation: gtk::Orientation::Vertical,
32                set_spacing: 5,
33                set_margin_all: 5,
34
35                gtk::Button {
36                    set_label: "Increment",
37                    connect_clicked => AppMsg::Increment,
38                },
39
40                gtk::Button {
41                    set_label: "Decrement",
42                    connect_clicked => AppMsg::Decrement,
43                },
44
45                gtk::Label {
46                    #[watch]
47                    set_label: &format!("Counter: {}", model.counter),
48                    set_margin_all: 5,
49                }
50            }
51        }
52    }
53
54    fn init_loading_widgets(root: Self::Root) -> Option<LoadingWidgets> {
55        view! {
56            #[local]
57            root {
58                set_title: Some("Simple app"),
59                set_default_size: (300, 100),
60
61                // This will be removed automatically by
62                // LoadingWidgets when the full view has loaded
63                #[name(spinner)]
64                gtk::Spinner {
65                    start: (),
66                    set_halign: gtk::Align::Center,
67                }
68            }
69        }
70        Some(LoadingWidgets::new(root, spinner))
71    }
72
73    // Initialize the component.
74    async fn init(
75        counter: Self::Init,
76        root: Self::Root,
77        sender: AsyncComponentSender<Self>,
78    ) -> AsyncComponentParts<Self> {
79        tokio::time::sleep(Duration::from_secs(1)).await;
80
81        let model = AppModel { counter };
82
83        // Insert the code generation of the view! macro here
84        let widgets = view_output!();
85
86        AsyncComponentParts { model, widgets }
87    }
88
89    async fn update(
90        &mut self,
91        msg: Self::Input,
92        _sender: AsyncComponentSender<Self>,
93        _root: &Self::Root,
94    ) {
95        tokio::time::sleep(Duration::from_secs(1)).await;
96        match msg {
97            AppMsg::Increment => {
98                self.counter = self.counter.wrapping_add(1);
99            }
100            AppMsg::Decrement => {
101                self.counter = self.counter.wrapping_sub(1);
102            }
103        }
104    }
105}
106
107fn main() {
108    let app = RelmApp::new("relm4.example.simple_async");
109    app.run_async::<AppModel>(0);
110}