1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::{
    core::{ni18n_f, Database},
    plugins::{PluginName, PluginSummaryRow},
    prelude::*,
};
use gtk::{glib, subclass::prelude::*};

mod imp {
    use crate::{core::Database, plugins::PluginSummaryRow, prelude::*};
    use adw::subclass::prelude::*;
    use gtk::{gio, glib, prelude::*, CompositeTemplate};

    #[derive(Debug, CompositeTemplate, Default)]
    #[template(resource = "/dev/Cogitri/Health/ui/plugins/activities/summary.ui")]
    pub struct PluginActivitiesSummaryRow {
        #[template_child]
        pub label: TemplateChild<gtk::Label>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for PluginActivitiesSummaryRow {
        const NAME: &'static str = "HealthPluginActivitiesSummaryRow";
        type ParentType = PluginSummaryRow;
        type Type = super::PluginActivitiesSummaryRow;

        fn class_init(klass: &mut Self::Class) {
            Self::bind_template(klass);
        }

        fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
            obj.init_template();
        }
    }

    impl ObjectImpl for PluginActivitiesSummaryRow {
        fn constructed(&self) {
            self.parent_constructed();
            let obj = self.obj();

            Database::instance().connect_activities_updated(glib::clone!(@weak obj => move |_| {
                gtk_macros::spawn!(async move {
                    obj.update().await;
                });
            }));
        }
    }
    impl WidgetImpl for PluginActivitiesSummaryRow {}
    impl ListBoxRowImpl for PluginActivitiesSummaryRow {}
    impl PreferencesRowImpl for PluginActivitiesSummaryRow {}
    impl ActionRowImpl for PluginActivitiesSummaryRow {}
    impl PluginSummaryRowImpl for PluginActivitiesSummaryRow {
        fn update(&self, obj: &PluginSummaryRow) -> PinnedResultFuture<()> {
            Box::pin(gio::GioFuture::new(
                obj,
                glib::clone!(@weak obj => move |_, _, send| {
                    gtk_macros::spawn!(async move {
                        obj.downcast_ref::<super::PluginActivitiesSummaryRow>()
                            .unwrap()
                            .update()
                            .await;
                        send.resolve(Ok(()));
                    });
                }),
            ))
        }
    }
}

glib::wrapper! {
    /// An implementation of [PluginSummaryRow] giving the user a quick glance at their active minutes.
    pub struct PluginActivitiesSummaryRow(ObjectSubclass<imp::PluginActivitiesSummaryRow>)
    @extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow, PluginSummaryRow,
    @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}

impl PluginActivitiesSummaryRow {
    pub fn new(name: PluginName) -> Self {
        glib::Object::builder()
            .property("plugin-name", name.as_ref())
            .property("activatable", true)
            .build()
    }

    pub async fn update(&self) {
        let imp = self.imp();
        let active_minutes_today: i64 = Database::instance()
            .activities_min(glib::DateTime::local().add_days(-1).unwrap())
            .await
            .unwrap_or_default()
            .iter()
            .map(|s| s.duration().as_minutes())
            .sum();
        imp.label.set_label(&ni18n_f(
            "{} active minute today",
            "{} active minutes today",
            active_minutes_today as u32,
            &[&active_minutes_today.to_string()],
        ))
    }
}

#[cfg(test)]
mod test {
    use super::{PluginActivitiesSummaryRow, PluginName};
    use crate::utils::init_gtk;

    #[gtk::test]
    fn new() {
        init_gtk();
        PluginActivitiesSummaryRow::new(PluginName::Activities);
    }
}