[gnome-shell/wip/fmuellner/notification-redux+sass: 20/61] dateMenu: Add world clock section



commit 3389e5e0da67950d70ddf2138094493a23042dd3
Author: Florian Müllner <fmuellner gnome org>
Date:   Sat Feb 7 00:47:27 2015 +0100

    dateMenu: Add world clock section
    
    Rather than just offering to open Clocks when installed, pick up
    configured locations and display their time directly in the popup.

 data/theme/_common.scss |    8 ++
 js/ui/dateMenu.js       |  170 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 159 insertions(+), 19 deletions(-)
---
diff --git a/data/theme/_common.scss b/data/theme/_common.scss
index f9ba573..9df036b 100644
--- a/data/theme/_common.scss
+++ b/data/theme/_common.scss
@@ -703,6 +703,7 @@ StScrollBar {
 
     .calendar,
     .datemenu-today-button,
+    .datemenu-displays-box,
     .message-list-sections {
       margin: 0 1.5em;
     }
@@ -713,6 +714,7 @@ StScrollBar {
     }
 
     .datemenu-today-button,
+    .world-clocks-button,
     .message-list-section-title {
       border-radius: 4px;
       padding: .4em;
@@ -727,6 +729,7 @@ StScrollBar {
     }
 
     .datemenu-today-button,
+    .world-clocks-button,
     .message-list-section-title {
       &:hover,&:focus { background-color: lighten($bg_color,5%); }
       &:active {
@@ -742,11 +745,16 @@ StScrollBar {
       font-size: 1.5em;
     }
 
+    .world-clocks-header,
     .message-list-section-title {
       color: darken($fg_color,40%);
       font-weight: bold;
     }
 
+    .world-clocks-grid {
+      spacing-rows: 0.4em;
+    }
+
     .calendar-month-label {
       color: darken($fg_color,5%);
       font-weight: bold;
diff --git a/js/ui/dateMenu.js b/js/ui/dateMenu.js
index dc6ea83..b71aad8 100644
--- a/js/ui/dateMenu.js
+++ b/js/ui/dateMenu.js
@@ -4,6 +4,8 @@ const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
 const GnomeDesktop = imports.gi.GnomeDesktop;
 const GObject = imports.gi.GObject;
+const Gtk = imports.gi.Gtk;
+const GWeather = imports.gi.GWeather;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 const Cairo = imports.cairo;
@@ -79,6 +81,145 @@ const TodayButton = new Lang.Class({
     }
 });
 
+const WorldClocksSection = new Lang.Class({
+    Name: 'WorldClocksSection',
+
+    _init: function() {
+        this._clock = new GnomeDesktop.WallClock();
+        this._settings = null;
+        this._clockNotifyId = 0;
+        this._changedId = 0;
+
+        this._locations = [];
+
+        this.actor = new St.Button({ style_class: 'world-clocks-button',
+                                     x_fill: true,
+                                     can_focus: true });
+        this.actor.connect('clicked', Lang.bind(this,
+            function() {
+                let app = this._getClockApp();
+                app.activate();
+
+                Main.overview.hide();
+                Main.panel.closeCalendar();
+            }));
+
+        let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
+        this._grid = new St.Widget({ style_class: 'world-clocks-grid',
+                                     layout_manager: layout });
+        layout.hookup_style(this._grid);
+
+        this.actor.child = this._grid;
+
+        Shell.AppSystem.get_default().connect('installed-changed',
+                                              Lang.bind(this, this._sync));
+        this._sync();
+    },
+
+    _getClockApp: function() {
+        return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
+    },
+
+    _sync: function() {
+        this.actor.visible = (this._getClockApp() != null);
+
+        if (this.actor.visible) {
+            if (!this._settings) {
+                this._settings = new Gio.Settings({ schema_id: 'org.gnome.clocks' });
+                this._changedId =
+                    this._settings.connect('changed::world-clocks',
+                                           Lang.bind(this, this._clocksChanged));
+                this._clocksChanged();
+            }
+        } else {
+            if (this._settings)
+                this._settings.disconnect(this._changedId);
+            this._settings = null;
+            this._changedId = 0;
+        }
+    },
+
+    _clocksChanged: function() {
+        this._grid.destroy_all_children();
+        this._locations = [];
+
+        let world = GWeather.Location.get_world();
+        let clocks = this._settings.get_value('world-clocks').deep_unpack();
+        for (let i = 0; i < clocks.length; i++) {
+            let l = world.deserialize(clocks[i].location);
+            this._locations.push({ location: l });
+        }
+
+        this._locations.sort(function(a, b) {
+            return a.location.get_timezone().get_offset() -
+                   b.location.get_timezone().get_offset();
+        });
+
+        let layout = this._grid.layout_manager;
+        let title = (this._locations.length == 0) ? _("Add world clocks…")
+                                                  : _("World Clocks");
+        let header = new St.Label({ style_class: 'world-clocks-header',
+                                    x_align: Clutter.ActorAlign.START,
+                                    text: title });
+        layout.attach(header, 0, 0, 2, 1);
+
+        for (let i = 0; i < this._locations.length; i++) {
+            let l = this._locations[i].location;
+
+            let label = new St.Label({ style_class: 'world-clocks-city',
+                                       text: l.get_city_name(),
+                                       x_align: Clutter.ActorAlign.START,
+                                       x_expand: true });
+
+            let time = new St.Label({ style_class: 'world-clocks-time',
+                                      x_align: Clutter.ActorAlign.END,
+                                      x_expand: true });
+
+            if (this._grid.text_direction == Clutter.TextDirection.RTL) {
+                layout.attach(time, 0, i + 1, 1, 1);
+                layout.attach(label, 1, i + 1, 1, 1);
+            } else {
+                layout.attach(label, 0, i + 1, 1, 1);
+                layout.attach(time, 1, i + 1, 1, 1);
+            }
+
+            this._locations[i].actor = time;
+        }
+
+        if (this._grid.get_n_children() > 1) {
+            if (!this._clockNotifyId)
+                this._clockNotifyId =
+                    this._clock.connect('notify::clock', Lang.bind(this, this._updateLabels));
+            this._updateLabels();
+        } else {
+            if (this._clockNotifyId)
+                this._clock.disconnect(this._clockNotifyId);
+            this._clockNotifyId = 0;
+        }
+    },
+
+    _updateLabels: function() {
+        let desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
+        let clockFormat = desktopSettings.get_string('clock-format');
+        let hasAmPm = new Date().toLocaleFormat('%p') != '';
+
+        let format;
+        if (clockFormat == '24h' || !hasAmPm)
+            /* Translators: Time in 24h format */
+            format = N_("%H\u2236%M");
+        else
+            /* Translators: Time in 12h format */
+            format = N_("%l\u2236%M %p");
+
+        for (let i = 0; i < this._locations.length; i++) {
+            let l = this._locations[i];
+            let tz = GLib.TimeZone.new(l.location.get_timezone().get_tzid());
+            let now = GLib.DateTime.new_now(tz);
+            l.actor.text = now.format(format);
+        }
+    }
+});
+
 const DateMenuButton = new Lang.Class({
     Name: 'DateMenuButton',
     Extends: PanelMenu.Button,
@@ -130,15 +271,18 @@ const DateMenuButton = new Lang.Class({
 
         vbox.add(this._calendar.actor);
 
-        let separator = new PopupMenu.PopupSeparatorMenuItem();
-        vbox.add(separator.actor, { y_align: St.Align.END, expand: true, y_fill: false });
+        let scroll = new St.ScrollView({ style_class: 'vfade',
+                                         x_expand: true, x_fill: true,
+                                         overlay_scrollbars: true });
+        scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
+        vbox.add_actor(scroll);
 
-        this._openClocksItem = new PopupMenu.PopupMenuItem(_("Open Clocks"));
-        this._openClocksItem.connect('activate', Lang.bind(this, this._onOpenClocksActivate));
-        vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
+        let displaysBox = new St.BoxLayout({ vertical: true,
+                                             style_class: 'datemenu-displays-box' });
+        scroll.add_actor(displaysBox);
 
-        Shell.AppSystem.get_default().connect('installed-changed',
-                                              Lang.bind(this, this._updateEventsVisibility));
+        this._clocksItem = new WorldClocksSection();
+        displaysBox.add(this._clocksItem.actor, { x_fill: true });
 
 
         // Done with hbox for calendar and event list
@@ -152,8 +296,6 @@ const DateMenuButton = new Lang.Class({
 
     _updateEventsVisibility: function() {
         let visible = this._eventSource.hasCalendars;
-        this._openClocksItem.actor.visible = visible &&
-            (this._getClockApp() != null);
         this._messageList.actor.visible = visible;
     },
 
@@ -184,15 +326,5 @@ const DateMenuButton = new Lang.Class({
         }
         this._setEventSource(eventSource);
         this._updateEventsVisibility();
-    },
-
-    _getClockApp: function() {
-        return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
-    },
-
-    _onOpenClocksActivate: function() {
-        this.menu.close();
-        let app = this._getClockApp();
-        app.activate();
     }
 });


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