azalea_shell/factory/notification/
mod.rs

1use gtk::{gdk, glib, prelude::*};
2use relm4::{FactorySender, prelude::*};
3
4use crate::{component::image, service::dbus::notification};
5
6pub struct Model {
7    notification: notification::service::Notification,
8    image: relm4::Controller<image::Model>,
9    has_image: bool,
10    // image: Option<gdk::Texture>,
11}
12
13#[derive(Debug)]
14pub enum Input {
15    Close,
16    // TODO: Action(String)
17}
18
19#[derive(Debug)]
20pub enum Output {
21    Close(u32),
22    // TODO: Action(String)
23}
24
25#[relm4::factory(pub)]
26impl FactoryComponent for Model {
27    type Index = u32;
28    type Init = notification::service::Notification;
29    type Input = Input;
30    type Output = Output;
31    type CommandOutput = ();
32    type ParentWidget = gtk::Box;
33
34    view! {
35        #[root]
36        gtk::Box {
37            gtk::Frame {
38                set_visible: self.has_image,
39                set_child: Some(self.image.widget()),
40            },
41
42            gtk::Box {
43                set_css_classes: &[
44                    "azalea-padding",
45                ],
46                set_orientation: gtk::Orientation::Vertical,
47                set_spacing: 12,
48                set_vexpand: true,
49                set_hexpand: true,
50
51                gtk::Label {
52                    set_css_classes: &[
53                        "azalea-primary-fg",
54                    ],
55                    #[watch]
56                    set_label: &self.notification.summary,
57
58                    set_max_width_chars: 30,
59                    set_wrap: true,
60                    set_halign: gtk::Align::Start,
61                    set_valign: gtk::Align::Start,
62                },
63
64                gtk::Label {
65                    #[watch]
66                    set_label: &self.notification.body,
67
68                    set_max_width_chars: 30,
69                    set_wrap: true,
70                    set_halign: gtk::Align::Start,
71                    set_valign: gtk::Align::Center,
72                },
73            },
74
75            gtk::Button {
76                set_css_classes: &[
77                    "azalea-padding",
78                ],
79                set_halign: gtk::Align::End,
80                set_label: "X",
81                connect_clicked => Input::Close
82            },
83        }
84    }
85
86    fn init_model(notification: Self::Init, _index: &u32, _sender: FactorySender<Self>) -> Self {
87        let mut model = Self {
88            has_image: false,
89            image: image::Model::builder()
90                .launch(image::Init {
91                    fallback: None,
92                    width: None,
93                    height: Some(100),
94                })
95                .detach(),
96            notification: notification.clone(),
97        };
98
99        match notification.image.clone() {
100            Some(image) => {
101                model.has_image = true;
102                match image {
103                    notification::service::Image::Data {
104                        width,
105                        height,
106                        rowstride,
107                        has_alpha,
108                        bits_per_sample,
109                        channels: _,
110                        data,
111                    } => {
112                        let pixbuf = gdk::gdk_pixbuf::Pixbuf::from_bytes(
113                            &glib::Bytes::from_owned(data),
114                            gtk::gdk_pixbuf::Colorspace::Rgb,
115                            has_alpha,
116                            bits_per_sample,
117                            width,
118                            height,
119                            rowstride,
120                        );
121
122                        drop(model.image.sender().send(image::Input::LoadPixbuf(pixbuf)));
123                    }
124                    notification::service::Image::Path(path) => {
125                        drop(model.image.sender().send(image::Input::LoadImage(path)));
126                    }
127                }
128            }
129            None => {
130                if notification.app_icon != "" {
131                    model.has_image = true;
132                    println!("{}", notification.app_icon);
133                    drop(
134                        model
135                            .image
136                            .sender()
137                            .send(image::Input::LoadImage(notification.app_icon)),
138                    );
139                }
140            }
141        };
142
143        model
144    }
145
146    fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
147        match message {
148            Input::Close => drop(sender.output(Output::Close(self.notification.id))),
149        }
150    }
151}