on xenial help sign in
Improve the appearance and functionality of datetime and session indicators in Unity8 desktop.

Approved by: Nick Dedekind

commit06831ba3173f9ba6a5549da180821f9ef8f1171e authorLukáš Tinkl <lukas.tinkl@canonical.com> dateFri 25 Sep 2015, 12:12 (11 years ago) parentabf56e4fea392c
11 files changed+207−44
plugins/Utils/CMakeLists.txt+1 plugins/Utils/plugin.cpp+3 plugins/Utils/timezoneFormatter.cpp+35 plugins/Utils/timezoneFormatter.h+32 po/unity8.pot+36−34 qml/Panel/IndicatorItem.qml+1−1 qml/Panel/IndicatorPage.qml+1−1 qml/Panel/Indicators/IndicatorDelegate.qml+1−1 qml/Panel/Indicators/MenuItemFactory.qml+93−5 qml/Panel/Indicators/MessageMenuItemFactory.qml+1−1 qml/Panel/Indicators/client/IndicatorRepresentation.qml+3−1
plugins/Utils/CMakeLists.txt+1
@@ -23,6 +23,7 @@ set(QMLPLUGIN_SRC
2323 windowscreenshotprovider.cpp
2424 easingcurve.cpp
2525 windowstatestorage.cpp
26+ timezoneFormatter.cpp
2627 plugin.cpp
2728 )
2829
plugins/Utils/plugin.cpp+3
@@ -36,6 +36,7 @@
3636#include "windowscreenshotprovider.h"
3737#include "windowstatestorage.h"
3838#include "constants.h"
39+#include "timezoneFormatter.h"
3940
4041static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
4142{
@@ -67,6 +68,8 @@ void UtilsPlugin::registerTypes(const char *uri)
6768 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
6869 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
6970 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
71+ qmlRegisterSingletonType<TimezoneFormatter>(uri, 0, 1, "TimezoneFormatter",
72+ [](QQmlEngine*, QJSEngine*) -> QObject* { return new TimezoneFormatter; });
7073 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
7174}
7275
plugins/Utils/timezoneFormatter.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QTimeZone>
18+
19+#include "timezoneFormatter.h"
20+
21+TimezoneFormatter::TimezoneFormatter(QObject *parent)
22+ : QObject(parent)
23+{
24+}
25+
26+QString TimezoneFormatter::currentTimeInTimezone(const QVariant &tzId) const
27+{
28+ QTimeZone tz(tzId.toByteArray());
29+ if (tz.isValid()) {
30+ const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz);
31+ // return locale-aware string in the form "day, hh:mm", e.g. "Mon 14:30" or "Mon 1:30 pm"
32+ return QStringLiteral("%1 %2").arg(now.toString("ddd")).arg(now.time().toString(Qt::DefaultLocaleShortDate));
33+ }
34+ return QString();
35+}
plugins/Utils/timezoneFormatter.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef TIMEZONE_FORMATTER_H
18+#define TIMEZONE_FORMATTER_H
19+
20+#include <QObject>
21+
22+class TimezoneFormatter : public QObject
23+{
24+ Q_OBJECT
25+public:
26+ TimezoneFormatter(QObject * parent = nullptr);
27+ ~TimezoneFormatter() = default;
28+
29+ Q_INVOKABLE QString currentTimeInTimezone(const QVariant &tzId) const;
30+};
31+
32+#endif
po/unity8.pot+36−34
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2015-08-25 14:53+0200\n"
11+"POT-Creation-Date: 2015-09-16 00:49+0200\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,7 +18,7 @@ msgstr ""
1818"Content-Transfer-Encoding: 8bit\n"
1919"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
2020
21−#: plugins/LightDM/Greeter.cpp:112
21+#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
2323msgstr ""
2424
@@ -134,83 +134,83 @@ msgid_plural "Please wait %1 minutes and then try again…"
134134msgstr[0] ""
135135msgstr[1] ""
136136
137−#: qml/Components/Dialogs.qml:112
137+#: qml/Components/Dialogs.qml:115
138138msgctxt "Title: Lock/Log out dialog"
139139msgid "Log out"
140140msgstr ""
141141
142−#: qml/Components/Dialogs.qml:113
142+#: qml/Components/Dialogs.qml:116
143143msgid "Are you sure you want to log out?"
144144msgstr ""
145145
146−#: qml/Components/Dialogs.qml:115
146+#: qml/Components/Dialogs.qml:118
147147msgctxt "Button: Lock the system"
148148msgid "Lock"
149149msgstr ""
150150
151−#: qml/Components/Dialogs.qml:122
151+#: qml/Components/Dialogs.qml:125
152152msgctxt "Button: Log out from the system"
153153msgid "Log Out"
154154msgstr ""
155155
156−#: qml/Components/Dialogs.qml:129 qml/Components/Dialogs.qml:162
157−#: qml/Components/Dialogs.qml:221
156+#: qml/Components/Dialogs.qml:132 qml/Components/Dialogs.qml:165
157+#: qml/Components/Dialogs.qml:224
158158msgid "Cancel"
159159msgstr ""
160160
161−#: qml/Components/Dialogs.qml:141
161+#: qml/Components/Dialogs.qml:144
162162msgctxt "Title: Reboot/Shut down dialog"
163163msgid "Shut down"
164164msgstr ""
165165
166−#: qml/Components/Dialogs.qml:142
166+#: qml/Components/Dialogs.qml:145
167167msgid "Are you sure you want to shut down?"
168168msgstr ""
169169
170−#: qml/Components/Dialogs.qml:144
170+#: qml/Components/Dialogs.qml:147
171171msgctxt "Button: Reboot the system"
172172msgid "Reboot"
173173msgstr ""
174174
175−#: qml/Components/Dialogs.qml:153
175+#: qml/Components/Dialogs.qml:156
176176msgctxt "Button: Shut down the system"
177177msgid "Shut down"
178178msgstr ""
179179
180−#: qml/Components/Dialogs.qml:175
180+#: qml/Components/Dialogs.qml:178
181181msgctxt "Title: Reboot dialog"
182182msgid "Reboot"
183183msgstr ""
184184
185−#: qml/Components/Dialogs.qml:176
185+#: qml/Components/Dialogs.qml:179
186186msgid "Are you sure you want to reboot?"
187187msgstr ""
188188
189−#: qml/Components/Dialogs.qml:178
189+#: qml/Components/Dialogs.qml:181
190190msgid "No"
191191msgstr ""
192192
193−#: qml/Components/Dialogs.qml:185
193+#: qml/Components/Dialogs.qml:188
194194msgid "Yes"
195195msgstr ""
196196
197−#: qml/Components/Dialogs.qml:200
197+#: qml/Components/Dialogs.qml:203
198198msgctxt "Title: Power off/Restart dialog"
199199msgid "Power"
200200msgstr ""
201201
202−#: qml/Components/Dialogs.qml:201
202+#: qml/Components/Dialogs.qml:204
203203msgid ""
204204"Are you sure you would like\n"
205205"to power off?"
206206msgstr ""
207207
208−#: qml/Components/Dialogs.qml:203
208+#: qml/Components/Dialogs.qml:206
209209msgctxt "Button: Power off the system"
210210msgid "Power off"
211211msgstr ""
212212
213−#: qml/Components/Dialogs.qml:212
213+#: qml/Components/Dialogs.qml:215
214214msgctxt "Button: Restart the system"
215215msgid "Restart"
216216msgstr ""
@@ -271,8 +271,10 @@ msgstr ""
271271msgid "Less..."
272272msgstr ""
273273
274−#: qml/Dash/Previews/PreviewCommentInput.qml:61
275−#: qml/Dash/Previews/PreviewRatingInput.qml:169
274+#: qml/Dash/Previews/PreviewCommentInput.qml:68
275+#: qml/Dash/Previews/PreviewRatingInput.qml:174
276+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:148
277+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:205
276278msgid "Send"
277279msgstr ""
278280
@@ -387,62 +389,62 @@ msgstr ""
387389msgid "Conference"
388390msgstr ""
389391
390−#: qml/Panel/Indicators/MenuItemFactory.qml:674
392+#: qml/Panel/Indicators/MenuItemFactory.qml:718
391393msgid "Nothing is playing"
392394msgstr ""
393395
394−#: qml/Panel/Indicators/MenuItemFactory.qml:803
396+#: qml/Panel/Indicators/MenuItemFactory.qml:847
395397#, qt-format
396398msgid "%1 hour"
397399msgid_plural "%1 hours"
398400msgstr[0] ""
399401msgstr[1] ""
400402
401−#: qml/Panel/Indicators/MenuItemFactory.qml:807
403+#: qml/Panel/Indicators/MenuItemFactory.qml:851
402404#, qt-format
403405msgid "%1 minute"
404406msgid_plural "%1 minutes"
405407msgstr[0] ""
406408msgstr[1] ""
407409
408−#: qml/Panel/Indicators/MenuItemFactory.qml:812
410+#: qml/Panel/Indicators/MenuItemFactory.qml:856
409411#, qt-format
410412msgid "%1 second"
411413msgid_plural "%1 seconds"
412414msgstr[0] ""
413415msgstr[1] ""
414416
415−#: qml/Panel/Indicators/MenuItemFactory.qml:815
417+#: qml/Panel/Indicators/MenuItemFactory.qml:859
416418msgid "0 seconds"
417419msgstr ""
418420
419421#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
420−#: qml/Panel/Indicators/MenuItemFactory.qml:817
422+#: qml/Panel/Indicators/MenuItemFactory.qml:861
421423#, qt-format
422424msgid "%1 remaining"
423425msgstr ""
424426
425−#: qml/Panel/Indicators/MenuItemFactory.qml:823
427+#: qml/Panel/Indicators/MenuItemFactory.qml:867
426428msgid "In queue…"
427429msgstr ""
428430
429−#: qml/Panel/Indicators/MenuItemFactory.qml:827
431+#: qml/Panel/Indicators/MenuItemFactory.qml:871
430432msgid "Downloading"
431433msgstr ""
432434
433−#: qml/Panel/Indicators/MenuItemFactory.qml:829
435+#: qml/Panel/Indicators/MenuItemFactory.qml:873
434436msgid "Paused, tap to resume"
435437msgstr ""
436438
437−#: qml/Panel/Indicators/MenuItemFactory.qml:831
439+#: qml/Panel/Indicators/MenuItemFactory.qml:875
438440msgid "Canceled"
439441msgstr ""
440442
441−#: qml/Panel/Indicators/MenuItemFactory.qml:833
443+#: qml/Panel/Indicators/MenuItemFactory.qml:877
442444msgid "Finished"
443445msgstr ""
444446
445−#: qml/Panel/Indicators/MenuItemFactory.qml:835
447+#: qml/Panel/Indicators/MenuItemFactory.qml:879
446448msgid "Failed, tap to retry"
447449msgstr ""
448450
qml/Panel/IndicatorItem.qml+1−1
@@ -243,7 +243,7 @@ IndicatorDelegate {
243243 return;
244244 }
245245
246− title = rootActionState.title ? rootActionState.title : "";
246+ title = rootActionState.title ? rootActionState.title : rootActionState.accessibleName;
247247 leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
248248 rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
249249 icons = rootActionState.icons;
qml/Panel/IndicatorPage.qml+1−1
@@ -23,7 +23,7 @@ IndicatorBase {
2323 id: main
2424
2525 //const
26− property string title: rootActionState.title
26+ property string title: rootActionState.title || rootActionState.accessibleName // some indicators don't expose a title but only the accessible-desc
2727 property alias highlightFollowsCurrentItem : mainMenu.highlightFollowsCurrentItem
2828 readonly property alias factory: _factory
2929
qml/Panel/Indicators/IndicatorDelegate.qml+1−1
@@ -21,5 +21,5 @@ import QtQuick 2.0
2121
2222IndicatorBase {
2323 readonly property bool indicatorVisible: rootActionState.indicatorVisible
24− readonly property string title: rootActionState.title
24+ readonly property string title: rootActionState.title || rootActionState.accessibleName
2525}
qml/Panel/Indicators/MenuItemFactory.qml+93−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013,2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -12,9 +12,6 @@
1212 *
1313 * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors:
17− * Nick Dedekind <nick.dedekind@canonical.com>
1815 */
1916
2017import QtQuick 2.0
@@ -23,7 +20,8 @@ import Ubuntu.Settings.Components 0.1
2320import QMenuModel 0.1
2421import Utils 0.1 as Utils
2522import Ubuntu.Components.ListItems 0.1 as ListItems
26−import Ubuntu.Components 1.1
23+import Ubuntu.Components 1.2
24+import Unity.Session 0.1
2725
2826Item {
2927 id: menuFactory
@@ -60,6 +58,12 @@ Item {
6058 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
6159 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
6260 "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
61+
62+ "com.canonical.indicator.calendar": calendarMenu,
63+ "com.canonical.indicator.location": timezoneMenu,
64+
65+ "indicator.user-menu-item": userMenuItem,
66+ "indicator.guest-menu-item": userMenuItem
6367 },
6468 "indicator-messages" : {
6569 "com.canonical.indicator.button" : messagesButtonMenu
@@ -422,6 +426,90 @@ Item {
422426 }
423427 }
424428
429+ Component {
430+ id: userMenuItem
431+
432+ Menus.UserSessionMenu {
433+ objectName: "userSessionMenu"
434+ highlightWhenPressed: false
435+
436+ property QtObject menuData: null
437+ property var menuModel: menuFactory.menuModel
438+ property int menuIndex: -1
439+
440+ name: menuData && menuData.label || "" // label is the user's real name
441+ iconSource: menuData && menuData.icon || ""
442+
443+ // would be better to compare with the logname but sadly the indicator doesn't expose that
444+ active: DBusUnitySessionService.RealName() !== "" ? DBusUnitySessionService.RealName() == name
445+ : DBusUnitySessionService.UserName() == name
446+
447+ onTriggered: {
448+ menuModel.activate(menuIndex);
449+ }
450+ }
451+ }
452+
453+ Component {
454+ id: calendarMenu
455+
456+ Menus.CalendarMenu {
457+ objectName: "calendarMenu"
458+ highlightWhenPressed: false
459+ focus: true
460+ }
461+ }
462+
463+ Component {
464+ id: timezoneMenu
465+
466+ Menus.TimeZoneMenu {
467+ id: tzMenuItem
468+ objectName: "timezoneMenu"
469+
470+ property QtObject menuData: null
471+ property var menuModel: menuFactory.menuModel
472+ property int menuIndex: -1
473+ property var extendedData: menuData && menuData.ext || undefined
474+ readonly property string tz: getExtendedProperty(extendedData, "xCanonicalTimezone", "UTC")
475+ property var updateTimer: Timer {
476+ repeat: true
477+ running: tzMenuItem.visible // only run when we're open
478+ onTriggered: tzMenuItem.time = Utils.TimezoneFormatter.currentTimeInTimezone(tzMenuItem.tz)
479+ }
480+
481+ city: menuData && menuData.label || ""
482+ time: Utils.TimezoneFormatter.currentTimeInTimezone(tz)
483+ enabled: menuData && menuData.sensitive || false
484+
485+ onMenuModelChanged: {
486+ loadAttributes();
487+ }
488+ onMenuIndexChanged: {
489+ loadAttributes();
490+ }
491+ onTriggered: {
492+ tzActionGroup.setLocation.activate(tz);
493+ }
494+
495+ QDBusActionGroup {
496+ id: tzActionGroup
497+ busType: DBus.SessionBus
498+ busName: "com.canonical.indicator.datetime"
499+ objectPath: "/com/canonical/indicator/datetime"
500+
501+ property variant setLocation: action("set-location")
502+
503+ Component.onCompleted: tzActionGroup.start()
504+ }
505+
506+ function loadAttributes() {
507+ if (!menuModel || menuIndex == -1) return;
508+ menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-timezone': 'string'});
509+ }
510+ }
511+ }
512+
425513 Component {
426514 id: wifiSection;
427515
qml/Panel/Indicators/MessageMenuItemFactory.qml+1−1
@@ -145,7 +145,7 @@ Loader {
145145 title: menuData && menuData.label || ""
146146 time: timeFormatter.timeString
147147 body: getExtendedProperty(extendedData, "xCanonicalText", "")
148− replyButtonText: getExtendedProperty(replyActionDescription, "label", "Send")
148+ replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send"))
149149 replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply")
150150 // icons
151151 avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
qml/Panel/Indicators/client/IndicatorRepresentation.qml+3−1
@@ -26,7 +26,9 @@ import "../.."
2626Page {
2727 id: root
2828
29− title: indicatorProperties && indicatorProperties.title ? indicatorProperties.title : ""
29+ title: indicatorProperties && indicatorProperties.title ? indicatorProperties.title :
30+ indicatorProperties && indicatorProperties.accessibleName ? indicatorProperties.accessibleName
31+ : ""
3032 property variant indicatorProperties
3133
3234 anchors.fill: parent