[gnome-clocks/wip/exalm/split: 4/7] timer: Split into multiple files



commit aaa28032ed68e17e1faf689d7d37cc7b39eb06a9
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sat May 23 04:01:44 2020 +0500

    timer: Split into multiple files
    
    Also fix ui file names.

 data/gnome-clocks.gresource.xml            |   6 +-
 data/ui/{timer.ui => timer-face.ui}        |   0
 data/ui/{timer_row.ui => timer-row.ui}     |   0
 data/ui/{timer_setup.ui => timer-setup.ui} |   0
 src/meson.build                            |   6 +-
 src/timer-face.vala                        | 144 +++++++++
 src/timer-item.vala                        | 142 +++++++++
 src/timer-row.vala                         | 144 +++++++++
 src/timer-setup-dialog.vala                |  43 +++
 src/timer-setup.vala                       | 114 +++++++
 src/timer.vala                             | 495 -----------------------------
 11 files changed, 595 insertions(+), 499 deletions(-)
---
diff --git a/data/gnome-clocks.gresource.xml b/data/gnome-clocks.gresource.xml
index aff772b..34d6935 100644
--- a/data/gnome-clocks.gresource.xml
+++ b/data/gnome-clocks.gresource.xml
@@ -17,9 +17,9 @@
     <file preprocess="xml-stripblanks">ui/alarm-setup-dialog.ui</file>
     <file preprocess="xml-stripblanks">ui/stopwatch-face.ui</file>
     <file preprocess="xml-stripblanks">ui/stopwatch-laps-row.ui</file>
-    <file preprocess="xml-stripblanks">ui/timer.ui</file>
-    <file preprocess="xml-stripblanks">ui/timer_row.ui</file>
-    <file preprocess="xml-stripblanks">ui/timer_setup.ui</file>
+    <file preprocess="xml-stripblanks">ui/timer-face.ui</file>
+    <file preprocess="xml-stripblanks">ui/timer-row.ui</file>
+    <file preprocess="xml-stripblanks">ui/timer-setup.ui</file>
   </gresource>
   <gresource prefix="/org/gnome/clocks/icons">
     <file alias="globe-symbolic.svg">gtk/icons/globe-symbolic.svg</file>
diff --git a/data/ui/timer.ui b/data/ui/timer-face.ui
similarity index 100%
rename from data/ui/timer.ui
rename to data/ui/timer-face.ui
diff --git a/data/ui/timer_row.ui b/data/ui/timer-row.ui
similarity index 100%
rename from data/ui/timer_row.ui
rename to data/ui/timer-row.ui
diff --git a/data/ui/timer_setup.ui b/data/ui/timer-setup.ui
similarity index 100%
rename from data/ui/timer_setup.ui
rename to data/ui/timer-setup.ui
diff --git a/src/meson.build b/src/meson.build
index 2079382..5493555 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -18,7 +18,11 @@ clocks_vala_sources = [
   'stopwatch-face.vala',
   'stopwatch-lap.vala',
   'stopwatch-laps-row.vala',
-  'timer.vala',
+  'timer-face.vala',
+  'timer-item.vala',
+  'timer-row.vala',
+  'timer-setup.vala',
+  'timer-setup-dialog.vala',
   'utils.vala',
   'widgets.vala',
   'window.vala',
diff --git a/src/timer-face.vala b/src/timer-face.vala
new file mode 100644
index 0000000..95aac80
--- /dev/null
+++ b/src/timer-face.vala
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013  Paolo Borelli <pborelli gnome org>
+ * Copyright (C) 2020  Bilal Elmoussaoui <bilal elmoussaoui gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+namespace Clocks {
+namespace Timer {
+
+[GtkTemplate (ui = "/org/gnome/clocks/ui/timer-face.ui")]
+public class Face : Gtk.Stack, Clocks.Clock {
+    private Setup timer_setup;
+    [GtkChild]
+    private Gtk.ListBox timers_list;
+    [GtkChild]
+    private Gtk.Box no_timer_container;
+    [GtkChild]
+    private Gtk.Button start_button;
+
+    public PanelId panel_id { get; construct set; }
+    public ButtonMode button_mode { get; set; default = NONE; }
+    public bool is_running { get; set; default = false; }
+    // Translators: Tooltip for the + button
+    public string? new_label { get; default = _("New Timer"); }
+
+    private ContentStore timers;
+    private GLib.Settings settings;
+    private Utils.Bell bell;
+    private GLib.Notification notification;
+
+    construct {
+        panel_id = TIMER;
+        transition_type = CROSSFADE;
+        timer_setup = new Setup ();
+
+        settings = new GLib.Settings ("org.gnome.clocks");
+        timers = new ContentStore ();
+
+        timers_list.bind_model (timers, (timer) => {
+            var row = new Row ((Item) timer);
+            row.deleted.connect (() => remove_timer ((Item) timer));
+            row.edited.connect (() => save ());
+            ((Item)timer).ring.connect (() => ring ());
+            ((Item)timer).notify["state"].connect (() => {
+                this.is_running = this.get_total_active_timers () != 0;
+            });
+            return row;
+        });
+
+        timers.items_changed.connect ( (added, removed, position) => {
+            if (this.timers.get_n_items () > 0) {
+                this.visible_child_name = "timers";
+                this.button_mode = NEW;
+            } else {
+                this.visible_child_name = "empty";
+                this.button_mode = NONE;
+            }
+            save ();
+        });
+
+        bell = new Utils.Bell ("complete");
+        notification = new GLib.Notification (_("Time is up!"));
+        notification.set_body (_("Timer countdown finished"));
+
+        no_timer_container.add (timer_setup);
+        no_timer_container.reorder_child (timer_setup, 1);
+        set_visible_child_name ("empty");
+
+        start_button.set_sensitive (false);
+        timer_setup.duration_changed.connect ((duration) => {
+            start_button.set_sensitive (duration != 0);
+        });
+        start_button.clicked.connect (() => {
+            var timer = this.timer_setup.get_timer ();
+            this.timers.add (timer);
+
+            timer.start ();
+        });
+        load ();
+    }
+
+    private int get_total_active_timers () {
+        var total_items = 0;
+        this.timers.foreach ((timer) => {
+            if (((Item)timer).state == Item.State.RUNNING) {
+                total_items += 1;
+            }
+        });
+        return total_items;
+    }
+
+    private void remove_timer (Item item) {
+        timers.remove (item);
+    }
+
+    public void activate_new () {
+        var dialog = new SetupDialog ((Gtk.Window) get_toplevel ());
+        dialog.response.connect ((dialog, response) => {
+            if (response == Gtk.ResponseType.ACCEPT) {
+                var timer = ((SetupDialog) dialog).timer_setup.get_timer ();
+                this.timers.add (timer);
+                timer.start ();
+            }
+            dialog.destroy ();
+        });
+        dialog.show ();
+    }
+
+    private void load () {
+        timers.deserialize (settings.get_value ("timers"), Item.deserialize);
+    }
+
+    private void save () {
+        settings.set_value ("timers", timers.serialize ());
+    }
+
+    public virtual signal void ring () {
+        var app = (Clocks.Application) GLib.Application.get_default ();
+        app.send_notification ("timer-is-up", notification);
+        bell.ring_once ();
+    }
+
+    public override void grab_focus () {
+        if (timers.get_n_items () == 0) {
+            start_button.grab_focus ();
+        }
+    }
+}
+
+} // namespace Timer
+} // namespace Clocks
diff --git a/src/timer-item.vala b/src/timer-item.vala
new file mode 100644
index 0000000..eaea6a1
--- /dev/null
+++ b/src/timer-item.vala
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2013  Paolo Borelli <pborelli gnome org>
+ * Copyright (C) 2020  Bilal Elmoussaoui <bilal elmoussaoui gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+namespace Clocks {
+namespace Timer {
+
+public class Item : Object, ContentItem {
+    public enum State {
+        STOPPED,
+        RUNNING,
+        PAUSED
+    }
+
+    public State state { get; private set; default = State.STOPPED; }
+
+    public string? name { get ; set; }
+    public int hours { get; set; default = 0; }
+    public int minutes { get; set; default = 0; }
+    public int seconds { get; set; default = 0; }
+
+    private double span;
+    private GLib.Timer timer;
+    private uint timeout_id;
+
+    public signal void ring ();
+    public signal void countdown_updated (int hours, int minutes, int seconds);
+
+    public int get_total_seconds () {
+        return hours * 3600 + minutes * 60 + seconds;
+    }
+
+    public void serialize (GLib.VariantBuilder builder) {
+        builder.open (new GLib.VariantType ("a{sv}"));
+        builder.add ("{sv}", "duration", new GLib.Variant.int32 (get_total_seconds ()));
+        if (name != null) {
+            builder.add ("{sv}", "name", new GLib.Variant.string ((string) name));
+        }
+        builder.close ();
+    }
+
+    public static Item? deserialize (Variant time_variant) {
+        string key;
+        Variant val;
+        int duration = 0;
+        string? name = null;
+
+        var iter = time_variant.iterator ();
+        while (iter.next ("{sv}", out key, out val)) {
+            switch (key) {
+                case "duration":
+                    duration = (int32) val;
+                    break;
+                case "name":
+                    name = (string) val;
+                    break;
+            }
+        }
+
+        return duration != 0 ? (Item?) new Item.from_seconds (duration, name) : null;
+    }
+
+    public Item.from_seconds (int seconds, string? name) {
+
+        int rest = 0;
+        int h = seconds / 3600;
+        rest = seconds - h * 3600;
+        int m = rest / 60;
+        int s = rest - m * 60;
+
+        this (h, m, s, name);
+    }
+
+    public Item (int h, int m, int s, string? name) {
+        Object (name: name);
+        hours = h;
+        minutes = m;
+        seconds = s;
+
+        span = get_total_seconds ();
+        timer = new GLib.Timer ();
+
+        timeout_id = 0;
+    }
+
+    public virtual signal void start () {
+        state = State.RUNNING;
+        timeout_id = GLib.Timeout.add (40, () => {
+            var e = timer.elapsed ();
+            if (state != State.RUNNING) {
+                return false;
+            }
+            if (e >= span) {
+                reset ();
+                ring ();
+                timeout_id = 0;
+                return false;
+            }
+            var elapsed = Math.ceil (span - e);
+            int h;
+            int m;
+            int s;
+            double r;
+            Utils.time_to_hms (elapsed, out h, out m, out s, out r);
+
+            countdown_updated (h, m, s);
+            return true;
+        });
+        timer.start ();
+    }
+
+    public virtual signal void pause () {
+        state = State.PAUSED;
+        span -= timer.elapsed ();
+        timer.stop ();
+    }
+
+    public virtual signal void reset () {
+        state = State.STOPPED;
+        span = get_total_seconds ();
+        timer.reset ();
+        timeout_id = 0;
+    }
+}
+
+} // namespace Timer
+} // namespace Clocks
diff --git a/src/timer-row.vala b/src/timer-row.vala
new file mode 100644
index 0000000..d26ebce
--- /dev/null
+++ b/src/timer-row.vala
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013  Paolo Borelli <pborelli gnome org>
+ * Copyright (C) 2020  Bilal Elmoussaoui <bilal elmoussaoui gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+namespace Clocks {
+namespace Timer {
+
+[GtkTemplate (ui = "/org/gnome/clocks/ui/timer-row.ui")]
+public class Row : Gtk.ListBoxRow {
+    public Item item {
+        get {
+            return _item;
+        }
+
+        construct set {
+            _item = value;
+
+            title.text = (string) _item.name;
+            title.bind_property ("text", _item, "name");
+            timer_name.label = (string) _item.name;
+            title.bind_property ("text", timer_name, "label");
+
+            _item.notify["name"].connect (() => edited ());
+        }
+    }
+    private Item _item;
+
+
+    [GtkChild]
+    private Gtk.Label countdown_label;
+
+    [GtkChild]
+    private Gtk.Label timer_name;
+
+    [GtkChild]
+    private Gtk.Stack name_stack;
+
+    [GtkChild]
+    private Gtk.Stack start_stack;
+    [GtkChild]
+    private Gtk.Stack reset_stack;
+    [GtkChild]
+    private Gtk.Stack delete_stack;
+
+    [GtkChild]
+    private Gtk.Button delete_button;
+    [GtkChild]
+    private Gtk.Entry title;
+
+    public signal void deleted ();
+    public signal void edited ();
+
+    public Row (Item item) {
+        Object (item: item);
+
+        item.countdown_updated.connect (this.update_countdown);
+        item.ring.connect (() => this.ring ());
+        item.start.connect (() => this.start ());
+        item.pause.connect (() => this.pause ());
+        item.reset.connect (() => this.reset ());
+        delete_button.clicked.connect (() => deleted ());
+
+        reset ();
+    }
+
+    [GtkCallback]
+    private void on_start_button_clicked () {
+        item.start ();
+    }
+
+    [GtkCallback]
+    private void on_pause_button_clicked () {
+        item.pause ();
+    }
+
+    [GtkCallback]
+    private void on_reset_button_clicked () {
+        item.reset ();
+    }
+
+    private void reset () {
+        reset_stack.visible_child_name = "empty";
+        delete_stack.visible_child_name = "button";
+
+        countdown_label.get_style_context ().remove_class ("timer-paused");
+        countdown_label.get_style_context ().remove_class ("timer-ringing");
+        countdown_label.get_style_context ().remove_class ("timer-running");
+        start_stack.visible_child_name = "start";
+        name_stack.visible_child_name = "edit";
+
+        update_countdown (item.hours, item.minutes, item.seconds);
+    }
+
+    private void start () {
+        countdown_label.get_style_context ().add_class ("timer-running");
+        countdown_label.get_style_context ().remove_class ("timer-ringing");
+        countdown_label.get_style_context ().remove_class ("timer-paused");
+
+        reset_stack.visible_child_name = "empty";
+        delete_stack.visible_child_name = "empty";
+
+        start_stack.visible_child_name = "pause";
+        name_stack.visible_child_name = "display";
+    }
+
+    private void ring () {
+        countdown_label.get_style_context ().add_class ("timer-ringing");
+        countdown_label.get_style_context ().remove_class ("timer-paused");
+        countdown_label.get_style_context ().remove_class ("timer-running");
+    }
+
+    private void pause () {
+        countdown_label.get_style_context ().add_class ("timer-paused");
+        countdown_label.get_style_context ().remove_class ("timer-ringing");
+        countdown_label.get_style_context ().remove_class ("timer-running");
+
+        reset_stack.visible_child_name = "button";
+        delete_stack.visible_child_name = "button";
+        start_stack.visible_child_name = "start";
+        name_stack.visible_child_name = "display";
+    }
+
+    private void update_countdown (int h, int m, int s ) {
+        countdown_label.set_text ("%02i ∶ %02i ∶ %02i".printf (h, m, s));
+    }
+}
+
+} // namespace Timer
+} // namespace Clocks
diff --git a/src/timer-setup-dialog.vala b/src/timer-setup-dialog.vala
new file mode 100644
index 0000000..e360ad8
--- /dev/null
+++ b/src/timer-setup-dialog.vala
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013  Paolo Borelli <pborelli gnome org>
+ * Copyright (C) 2020  Bilal Elmoussaoui <bilal elmoussaoui gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+namespace Clocks {
+namespace Timer {
+
+public class SetupDialog: Gtk.Dialog {
+    public Setup timer_setup;
+
+    public SetupDialog (Gtk.Window parent) {
+        Object (modal: true, transient_for: parent, title: _("New Timer"), use_header_bar: 1);
+        this.set_default_size (640, 360);
+
+        add_button (_("Cancel"), Gtk.ResponseType.CANCEL);
+        var create_button = add_button (_("Add"), Gtk.ResponseType.ACCEPT);
+        create_button.get_style_context ().add_class ("suggested-action");
+
+        timer_setup = new Setup ();
+        this.get_content_area ().add (timer_setup);
+        timer_setup.duration_changed.connect ((duration) => {
+            this.set_response_sensitive (Gtk.ResponseType.ACCEPT, duration != 0);
+        });
+    }
+}
+
+} // namespace Timer
+} // namespace Clocks
diff --git a/src/timer-setup.vala b/src/timer-setup.vala
new file mode 100644
index 0000000..3661378
--- /dev/null
+++ b/src/timer-setup.vala
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013  Paolo Borelli <pborelli gnome org>
+ * Copyright (C) 2020  Bilal Elmoussaoui <bilal elmoussaoui gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+namespace Clocks {
+namespace Timer {
+
+[GtkTemplate (ui = "/org/gnome/clocks/ui/timer-setup.ui")]
+public class Setup : Gtk.Box {
+    public signal void duration_changed (int seconds);
+    [GtkChild]
+    private Gtk.SpinButton h_spinbutton;
+    [GtkChild]
+    private Gtk.SpinButton m_spinbutton;
+    [GtkChild]
+    private Gtk.SpinButton s_spinbutton;
+
+    public Setup () {
+        var actions = new SimpleActionGroup ();
+        // The duration here represends a number of minutes
+        var duration_type = new GLib.VariantType ("i");
+        var set_duration_action = new SimpleAction ("set-duration", duration_type);
+        set_duration_action.activate.connect ((action, param) => {
+            var total_minutes = (int32) param;
+            var hours = total_minutes / 60;
+            var minutes = total_minutes - hours * 60;
+            this.h_spinbutton.value = hours;
+            this.m_spinbutton.value = minutes;
+        });
+        actions.add_action (set_duration_action);
+        insert_action_group ("timer-setup", actions);
+    }
+
+    private int get_duration () {
+        /**
+         * Gets the total duration of a timer in seconds
+         * */
+
+        var hours = (int)h_spinbutton.value;
+        var minutes = (int)m_spinbutton.value;
+        var seconds = (int)s_spinbutton.value;
+
+        return hours * 3600 + minutes * 60 + seconds;
+    }
+
+    public Item get_timer () {
+        return (new Item.from_seconds (get_duration (), ""));
+    }
+
+    [GtkCallback]
+    private void update_duration () {
+        duration_changed (get_duration ());
+    }
+
+    [GtkCallback]
+    private bool show_leading_zeros (Gtk.SpinButton spin_button) {
+        spin_button.set_text ("%02i".printf (spin_button.get_value_as_int ()));
+        return true;
+    }
+
+    [GtkCallback]
+    private int input_minutes (Gtk.SpinButton spin_button, out double new_value) {
+        int entered_value = int.parse (spin_button.get_text ());
+
+        // if input entered is not within bounds then it will carry the
+        // extra portion to hours field
+        if (entered_value > 59) {
+           int current_hours = h_spinbutton.get_value_as_int ();
+           h_spinbutton.set_value (double.min (99, current_hours + entered_value / 60));
+        }
+        new_value = entered_value % 60;
+        return 1;
+    }
+
+
+    [GtkCallback]
+    private int input_seconds (Gtk.SpinButton spin_button, out double new_value) {
+        int entered_value = int.parse (spin_button.get_text ());
+
+        // if input entered is not within bounds then it will carry the
+        // extra portion to minutes field and hours field accordingly
+        if (entered_value > 59) {
+            int current_minutes = m_spinbutton.get_value_as_int ();
+            int new_minutes = current_minutes + entered_value / 60;
+            if (new_minutes > 59) {
+                int current_hours = h_spinbutton.get_value_as_int ();
+                h_spinbutton.set_value (double.min (99, current_hours + new_minutes / 60));
+                new_minutes = new_minutes % 60;
+            }
+            m_spinbutton.set_value (new_minutes);
+
+        }
+        new_value = entered_value % 60;
+        return 1;
+    }
+}
+
+} // namespace Timer
+} // namespace Clocks


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]