azalea_shell/window/taskbar/widget/
time.rs

1use azalea_service::{LocalListenerHandle, StaticServiceManager};
2use gtk::prelude::*;
3use relm4::{Component, ComponentParts, ComponentSender, RelmWidgetExt, component};
4
5use crate::service;
6
7type Time = chrono::DateTime<chrono::Local>;
8
9crate::init! {
10    Model {
11        time: Time,
12        format: String,
13        _service_handle: LocalListenerHandle,
14    }
15
16    Config {
17        format: String,
18    }
19}
20
21#[derive(Debug)]
22pub enum Input {
23    Time(Time),
24}
25
26#[component(pub)]
27impl Component for Model {
28    type Init = Init;
29    type Input = Input;
30    type Output = ();
31    type CommandOutput = Input;
32
33    view! {
34        gtk::MenuButton {
35            #[wrap(Some)]
36            set_child = &gtk::Label {
37                #[watch]
38                set_label: &format!("{}", model.time.format(&model.format)),
39            },
40
41            #[wrap(Some)]
42            set_popover = &gtk::Popover {
43                gtk::Box {
44                    gtk::Box {
45                        set_valign: gtk::Align::Center,
46                        set_halign: gtk::Align::Center,
47                        set_orientation: gtk::Orientation::Vertical,
48                        inline_css: "padding: 0 60px 0 60px",
49
50                        gtk::Label {
51                            inline_css: "font-size: 50px",
52                            set_label: &format!("{}", model.time.format("%H:%M")),
53                        },
54
55                        gtk::Label {
56                            set_label: &format!("{}", model.time.format("%B %d, %Y")),
57                        },
58                    },
59
60                    gtk::Calendar { },
61                }
62            }
63        }
64    }
65
66    fn init(
67        init: Self::Init,
68        _root: Self::Root,
69        sender: ComponentSender<Self>,
70    ) -> ComponentParts<Self> {
71        let format = init.config.format;
72
73        let model = Model {
74            format: format.clone(),
75            time: chrono::Local::now(),
76            _service_handle: service::time::Service::filtered_forward_local(
77                sender.input_sender().clone(),
78                move |event| {
79                    use service::time::Output;
80
81                    let format_contains_time =
82                        |date_time: chrono::DateTime<chrono::Local>, time: &str| -> Option<Input> {
83                            if format.contains(time) {
84                                Some(Input::Time(date_time))
85                            } else {
86                                None
87                            }
88                        };
89
90                    match event {
91                        Output::Second(date_time) => format_contains_time(date_time, "%S"),
92                        Output::Minute(date_time) => format_contains_time(date_time, "%M"),
93                        Output::Hour(date_time) => format_contains_time(date_time, "%H"),
94                    }
95                },
96            ),
97        };
98
99        let widgets = view_output!();
100
101        ComponentParts { model, widgets }
102    }
103
104    fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>, _root: &Self::Root) {
105        match message {
106            Input::Time(time) => self.time = time,
107        }
108    }
109
110    fn update_cmd(
111        &mut self,
112        message: Self::CommandOutput,
113        _sender: ComponentSender<Self>,
114        _root: &Self::Root,
115    ) {
116        match message {
117            Input::Time(time) => self.time = time,
118        }
119    }
120}