1/*
2 * Copyright (C) 2013  Paolo Borelli <pborelli@gnome.org>
3 * Copyright (C) 2020  Bilal Elmoussaoui <bilal.elmoussaoui@gnome.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19
20namespace Clocks {
21namespace Timer {
22
23[GtkTemplate (ui = "/org/gnome/clocks/ui/timer-face.ui")]
24public class Face : Gtk.Stack, Clocks.Clock {
25    private Setup timer_setup;
26    [GtkChild]
27    private unowned Gtk.ListBox timers_list;
28    [GtkChild]
29    private unowned Gtk.Box no_timer_container;
30    [GtkChild]
31    private unowned Gtk.Button start_button;
32
33    public PanelId panel_id { get; construct set; }
34    public ButtonMode button_mode { get; set; default = NONE; }
35    public bool is_running { get; set; default = false; }
36    // Translators: Tooltip for the + button
37    public string? new_label { get; default = _("New Timer"); }
38
39    private ContentStore timers;
40    private GLib.Settings settings;
41    private Utils.Bell bell;
42    private GLib.Notification notification;
43
44    construct {
45        panel_id = TIMER;
46        transition_type = CROSSFADE;
47        timer_setup = new Setup ();
48
49        settings = new GLib.Settings ("org.gnome.clocks");
50        timers = new ContentStore ();
51
52        timers_list.bind_model (timers, (timer) => {
53            var row = new Row ((Item) timer);
54            row.deleted.connect (() => remove_timer ((Item) timer));
55            row.edited.connect (() => save ());
56            ((Item)timer).ring.connect (() => ring ());
57            ((Item)timer).notify["state"].connect (() => {
58                this.is_running = this.get_total_active_timers () != 0;
59            });
60            return row;
61        });
62
63        timers.items_changed.connect ( (added, removed, position) => {
64            if (this.timers.get_n_items () > 0) {
65                this.visible_child_name = "timers";
66                this.button_mode = NEW;
67            } else {
68                this.visible_child_name = "empty";
69                this.button_mode = NONE;
70            }
71            save ();
72        });
73
74        bell = new Utils.Bell ("complete");
75        notification = new GLib.Notification (_("Time is up!"));
76        notification.set_body (_("Timer countdown finished"));
77        notification.set_priority (HIGH);
78
79        no_timer_container.add (timer_setup);
80        no_timer_container.reorder_child (timer_setup, 1);
81        set_visible_child_name ("empty");
82
83        start_button.set_sensitive (false);
84        timer_setup.duration_changed.connect ((duration) => {
85            start_button.set_sensitive (duration != 0);
86        });
87        start_button.clicked.connect (() => {
88            var timer = this.timer_setup.get_timer ();
89            this.timers.add (timer);
90
91            timer.start ();
92        });
93        load ();
94    }
95
96    private int get_total_active_timers () {
97        var total_items = 0;
98        this.timers.foreach ((timer) => {
99            if (((Item)timer).state == Item.State.RUNNING) {
100                total_items += 1;
101            }
102        });
103        return total_items;
104    }
105
106    private void remove_timer (Item item) {
107        timers.remove (item);
108    }
109
110    public void activate_new () {
111        var dialog = new SetupDialog ((Gtk.Window) get_toplevel ());
112        dialog.response.connect ((dialog, response) => {
113            if (response == Gtk.ResponseType.ACCEPT) {
114                var timer = ((SetupDialog) dialog).timer_setup.get_timer ();
115                this.timers.add (timer);
116                timer.start ();
117            }
118            dialog.destroy ();
119        });
120        dialog.show ();
121    }
122
123    private void load () {
124        timers.deserialize (settings.get_value ("timers"), Item.deserialize);
125    }
126
127    private void save () {
128        settings.set_value ("timers", timers.serialize ());
129    }
130
131    public virtual signal void ring () {
132        var app = (Clocks.Application) GLib.Application.get_default ();
133        app.send_notification ("timer-is-up", notification);
134        bell.ring_once ();
135    }
136
137    public override void grab_focus () {
138        if (timers.get_n_items () == 0) {
139            start_button.grab_focus ();
140        }
141    }
142}
143
144} // namespace Timer
145} // namespace Clocks
146