From efc0ec474072347dc5b037400bbeb89861746f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Sat, 7 Feb 2015 00:47:27 +0100 Subject: [PATCH] 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. https://bugzilla.gnome.org/show_bug.cgi?id=744817 --- data/theme/gnome-shell-sass | 2 +- data/theme/gnome-shell.css | 9 ++ js/ui/dateMenu.js | 170 ++++++++++++++++++++++++++++++++---- 3 files changed, 161 insertions(+), 20 deletions(-) diff --git a/data/theme/gnome-shell-sass b/data/theme/gnome-shell-sass index f0fd5e109..3f8a86fc4 160000 --- a/data/theme/gnome-shell-sass +++ b/data/theme/gnome-shell-sass @@ -1 +1 @@ -Subproject commit f0fd5e109ff5499f42f7c6d31b4308b82f6b5879 +Subproject commit 3f8a86fc461e098a7d97cc601c72248645ef9190 diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 6d4f48e9c..1cab3005b 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -593,6 +593,7 @@ StScrollBar { .calendar, .datemenu-today-button, +.datemenu-displays-box, .message-list-sections { margin: 0 1.5em; } @@ -601,6 +602,7 @@ StScrollBar { padding-bottom: 3em; } .datemenu-today-button, +.world-clocks-button, .message-list-section-title { border-radius: 4px; padding: .4em; } @@ -612,10 +614,13 @@ StScrollBar { padding-right: .4em; } .datemenu-today-button:hover, .datemenu-today-button:focus, +.world-clocks-button:hover, +.world-clocks-button:focus, .message-list-section-title:hover, .message-list-section-title:focus { background-color: #454c4c; } .datemenu-today-button:active, +.world-clocks-button:active, .message-list-section-title:active { color: white; background-color: #215d9c; } @@ -623,10 +628,14 @@ StScrollBar { .datemenu-today-button .date-label { font-size: 1.5em; } +.world-clocks-header, .message-list-section-title { color: #8e8e80; font-weight: bold; } +.world-clocks-grid { + spacing-rows: 0.4em; } + .calendar-month-label { color: #e2e2df; font-weight: bold; diff --git a/js/ui/dateMenu.js b/js/ui/dateMenu.js index dc6ea835f..b71aad8ac 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(); } });