on xenial help sign in
more visual tweaks
f6749edNick Dedekind
plugins/Utils/CMakeLists.txt+1
@@ -13,6 +13,7 @@ include_directories(
13set(QMLPLUGIN_SRC
13set(QMLPLUGIN_SRC
14 qlimitproxymodelqml.cpp
14 qlimitproxymodelqml.cpp
15 qsortfilterproxymodelqml.cpp
15 qsortfilterproxymodelqml.cpp
16+ relativetimeformatter.cpp
16 timeformatter.cpp
17 timeformatter.cpp
17 unitymenumodelpaths.cpp
18 unitymenumodelpaths.cpp
18 easingcurve.cpp
19 easingcurve.cpp
plugins/Utils/plugin.cpp+2
@@ -28,6 +28,7 @@
28// local
28// local
29#include "qlimitproxymodelqml.h"
29#include "qlimitproxymodelqml.h"
30#include "qsortfilterproxymodelqml.h"
30#include "qsortfilterproxymodelqml.h"
31+#include "relativetimeformatter.h"
31#include "timeformatter.h"
32#include "timeformatter.h"
32#include "unitymenumodelpaths.h"
33#include "unitymenumodelpaths.h"
33#include "easingcurve.h"
34#include "easingcurve.h"
@@ -42,6 +43,7 @@ void UtilsPlugin::registerTypes(const char *uri)
42 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
43 qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
43 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
44 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
44 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
45 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
46+ qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
45}
47}
46
48
47void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
49void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
plugins/Utils/relativetimeformatter.cppnew file+195
@@ -0,0 +1,195 @@
1+
2+#include "relativetimeformatter.h"
3+
4+#include <QDateTime>
5+
6+#include <QDebug>
7+
8+#include <glib.h>
9+#include <locale.h>
10+#include <langinfo.h>
11+#include <libintl.h>
12+
13+RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent)
14+ : GDateTimeFormatter(parent)
15+{
16+}
17+
18+/* Check the system locale setting to see if the format is 24-hour
19+ time or 12-hour time */
20+gboolean
21+is_locale_12h(void)
22+{
23+ int i;
24+ static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", NULL};
25+ const char* t_fmt = nl_langinfo(T_FMT);
26+
27+ for (i=0; formats_24h[i]!=NULL; i++)
28+ if (strstr(t_fmt, formats_24h[i]) != NULL)
29+ return FALSE;
30+
31+ return TRUE;
32+}
33+
34+
35+typedef enum
36+{
37+ DATE_PROXIMITY_TODAY,
38+ DATE_PROXIMITY_YESTERDAY,
39+ DATE_PROXIMITY_WEEK,
40+ DATE_PROXIMITY_FAR
41+}
42+date_proximity_t;
43+
44+static date_proximity_t
45+getDateProximity(GDateTime* now, GDateTime* time)
46+{
47+ date_proximity_t prox = DATE_PROXIMITY_FAR;
48+ gint now_year, now_month, now_day;
49+ gint time_year, time_month, time_day;
50+
51+ // does it happen today?
52+ g_date_time_get_ymd(now, &now_year, &now_month, &now_day);
53+ g_date_time_get_ymd(time, &time_year, &time_month, &time_day);
54+ if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) {
55+ return DATE_PROXIMITY_TODAY;
56+ }
57+
58+ // does it happen tomorrow?
59+ GDateTime* tomorrow = g_date_time_add_days(now, -1);
60+ gint tom_year, tom_month, tom_day;
61+ g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day);
62+ if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day))
63+ return DATE_PROXIMITY_YESTERDAY;
64+ g_date_time_unref(tomorrow);
65+
66+ // does it happen this week?
67+ if (prox == DATE_PROXIMITY_FAR) {
68+ GDateTime* week = g_date_time_add_days(now, -6);
69+ GDateTime* week_bound = g_date_time_new_local(g_date_time_get_year(week),
70+ g_date_time_get_month(week),
71+ g_date_time_get_day_of_month(week),
72+ 23, 59, 59.9);
73+
74+ if (g_date_time_compare(time, week_bound) >= 0)
75+ prox = DATE_PROXIMITY_WEEK;
76+
77+ g_date_time_unref(week_bound);
78+ g_date_time_unref(week);
79+ }
80+
81+ return DATE_PROXIMITY_FAR;
82+}
83+
84+/**
85+ * _ a time today should be shown as just the time (e.g. “3:55 PM”)
86+ * _ a full-day event today should be shown as “Today”
87+ * _ a time any other day this week should be shown as the short version of the
88+ * day and time (e.g. “Wed 3:55 PM”)
89+ * _ a full-day event tomorrow should be shown as “Tomorrow”
90+ * _ a full-day event another day this week should be shown as the
91+ * weekday (e.g. “Friday”)
92+ * _ a time after this week should be shown as the short version of the day,
93+ * date, and time (e.g. “Wed 21 Apr 3:55 PM”)
94+ * _ a full-day event after this week should be shown as the short version of
95+ * the day and date (e.g. “Wed 21 Apr”).
96+ * _ in addition, when presenting the times of upcoming events, the time should
97+ * be followed by the timezone if it is different from the one the computer
98+ * is currently set to. For example, “Wed 3:55 PM UTC−5”.
99+ */
100+char* generate_full_format_string_at_time (GDateTime* now,
101+ GDateTime* then)
102+{
103+ GString* ret = g_string_new (NULL);
104+
105+ if (then != NULL) {
106+ const date_proximity_t prox = getDateProximity(now, then);
107+
108+ if (is_locale_12h()) {
109+ switch (prox) {
110+ case DATE_PROXIMITY_TODAY:
111+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
112+ This format string is used for showing, on a 12-hour clock, times that happened today.
113+ en_US example: "%l:%M %p" --> "1:00 PM" */
114+ g_string_assign (ret, gettext("%l:%M %p"));
115+ break;
116+
117+ case DATE_PROXIMITY_YESTERDAY:
118+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
119+ This format string is used for showing, on a 12-hour clock, times that happen yesterday.
120+ (\u2003 is a unicode em space which is slightly wider than a normal space.)
121+ en_US example: "Yesterday\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */
122+ g_string_assign (ret, gettext("Yesterday\u2003%l:%M %p"));
123+ break;
124+
125+ case DATE_PROXIMITY_WEEK:
126+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
127+ This format string is used for showing, on a 12-hour clock, times that happened in the last week.
128+ (\u2003 is a unicode em space which is slightly wider than a normal space.)
129+ en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */
130+ g_string_assign (ret, gettext("%a\u2003%l:%M %p"));
131+ break;
132+
133+ case DATE_PROXIMITY_FAR:
134+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
135+ This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
136+ (\u2003 is a unicode em space which is slightly wider than a normal space.)
137+ en_US example: "%a %d %b\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM"
138+ en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */
139+ g_string_assign (ret, gettext("%a %d %b\u2003%l:%M %p"));
140+ break;
141+ }
142+ } else {
143+ switch (prox) {
144+ case DATE_PROXIMITY_TODAY:
145+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
146+ This format string is used for showing, on a 24-hour clock, times that happened today.
147+ en_US example: "%H:%M" --> "13:00" */
148+ g_string_assign (ret, gettext("%H:%M"));
149+ break;
150+
151+ case DATE_PROXIMITY_YESTERDAY:
152+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
153+ This format string is used for showing, on a 24-hour clock, times that happen yesterday.
154+ (\u2003 is a unicode em space which is slightly wider than a normal space.)
155+ en_US example: "Yesterday\u2003%l:%M %p" --> "Tomorrow 13:00" */
156+ g_string_assign (ret, gettext("Yesterday\u2003%H:%M"));
157+ break;
158+
159+ case DATE_PROXIMITY_WEEK:
160+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
161+ This format string is used for showing, on a 24-hour clock, times that happened in the last week.
162+ (\u2003 is a unicode em space which is slightly wider than a normal space.)
163+ en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */
164+ g_string_assign (ret, gettext("%a\u2003%H:%M"));
165+ break;
166+
167+ case DATE_PROXIMITY_FAR:
168+ /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
169+ This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
170+ (\u2003 is a unicode em space which is slightly wider than a normal space.)
171+ en_US example: "%a %d %b\u2003%H:%M" --> "Fri Oct 31 13:00"
172+ en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00" */
173+ g_string_assign (ret, gettext("%a %d %b\u2003%H:%M"));
174+ break;
175+ }
176+ }
177+ }
178+
179+ return g_string_free (ret, FALSE);
180+}
181+
182+QString RelativeTimeFormatter::format() const
183+{
184+ GDateTime* now = g_date_time_new_from_unix_utc(QDateTime::currentMSecsSinceEpoch() / 1000);
185+ GDateTime* then = g_date_time_new_from_unix_local(time());
186+ char* time_format = generate_full_format_string_at_time(now, then);
187+
188+ QString str(QString::fromUtf8(time_format));
189+ g_free(time_format);
190+
191+ g_date_time_unref(now);
192+ g_date_time_unref(then);
193+
194+ return str;
195+}
plugins/Utils/relativetimeformatter.hnew file+15
@@ -0,0 +1,15 @@
1+#ifndef RELATIVETIMEFORMATTER_H
2+#define RELATIVETIMEFORMATTER_H
3+
4+#include "timeformatter.h"
5+
6+class RelativeTimeFormatter : public GDateTimeFormatter
7+{
8+ Q_OBJECT
9+public:
10+ RelativeTimeFormatter(QObject *parent = 0);
11+
12+ QString format() const override;
13+};
14+
15+#endif // RELATIVETIMEFORMATTER_H
plugins/Utils/timeformatter.h+1−1
@@ -33,7 +33,7 @@ public:
33 TimeFormatter(QObject *parent = 0);
33 TimeFormatter(QObject *parent = 0);
34 virtual ~TimeFormatter();
34 virtual ~TimeFormatter();
35
35
36− QString format() const;
36+ virtual QString format() const;
37 QString timeString() const;
37 QString timeString() const;
38 qint64 time() const;
38 qint64 time() const;
39
39
qml/Panel/Indicators.qml+2−1
@@ -187,7 +187,8 @@ Showable {
187 bottom: handle.top
187 bottom: handle.top
188 }
188 }
189 indicatorsModel: visibleIndicators.model
189 indicatorsModel: visibleIndicators.model
190− clip: !indicators.fullyOpened
190+ visible: indicators.fullyOpened || indicators.partiallyOpened
191+ clip: indicators.partiallyOpened
191 enabled: contentEnabled
192 enabled: contentEnabled
192
193
193 //small shadow gradient at bottom of menu
194 //small shadow gradient at bottom of menu
qml/Panel/Indicators/DefaultIndicatorPage.qml+2−8
@@ -124,16 +124,10 @@ IndicatorBase {
124 delegate: Loader {
124 delegate: Loader {
125 id: loader
125 id: loader
126 objectName: "menuItem" + index
126 objectName: "menuItem" + index
127− asynchronous: false
127+ asynchronous: true
128− visible: height > 0
128+ width: ListView.view.width
129
129
130 property int modelIndex: index
130 property int modelIndex: index
131−
132− anchors {
133− left: parent.left
134− right: parent.right
135− }
136−
137 sourceComponent: factory.load(model, identifier)
131 sourceComponent: factory.load(model, identifier)
138
132
139 onLoaded: {
133 onLoaded: {
qml/Panel/Indicators/MenuItemFactory.qml+44−8
@@ -46,6 +46,7 @@ Item {
46 "com.canonical.indicator.appointment" : appointmentMenu,
46 "com.canonical.indicator.appointment" : appointmentMenu,
47 "com.canonical.indicator.transfer" : transferMenu,
47 "com.canonical.indicator.transfer" : transferMenu,
48 "com.canonical.indicator.button-section" : buttonSectionMenu,
48 "com.canonical.indicator.button-section" : buttonSectionMenu,
49+ "com.canonical.indicator.link" : linkMenu,
49
50
50 "com.canonical.indicator.messages.messageitem" : messageItem,
51 "com.canonical.indicator.messages.messageitem" : messageItem,
51 "com.canonical.indicator.messages.sourceitem" : groupedMessage,
52 "com.canonical.indicator.messages.sourceitem" : groupedMessage,
@@ -223,9 +224,10 @@ Item {
223 menuModel.activate(menuIndex);
224 menuModel.activate(menuIndex);
224 }
225 }
225
226
227+ // FIXME : At the moment, the indicators aren't using
228+ // com.canonical.indicators.link for settings menu. Need to fudge it.
226 property bool settingsMenu: menuData.action.indexOf("settings") > -1
229 property bool settingsMenu: menuData.action.indexOf("settings") > -1
227− backColor: settingsMenu ? Qt.rgba(1,1,1,0.05) : "transparent"
230+ backColor: settingsMenu ? Qt.rgba(1,1,1,0.07) : "transparent"
228−
229 component: settingsMenu ? buttonForSettings : undefined
231 component: settingsMenu ? buttonForSettings : undefined
230 Component {
232 Component {
231 id: buttonForSettings
233 id: buttonForSettings
@@ -239,6 +241,37 @@ Item {
239 }
241 }
240 }
242 }
241
243
244+ Component {
245+ id: linkMenu;
246+
247+ Menus.StandardMenu {
248+ objectName: "linkMenu"
249+ property QtObject menuData: null
250+ property int menuIndex: -1
251+
252+ text: menuData && menuData.label || ""
253+ iconSource: menuData && menuData.icon || ""
254+ enabled: menuData && menuData.sensitive || false
255+
256+ onTriggered: {
257+ menuModel.activate(menuIndex);
258+ }
259+
260+ backColor: Qt.rgba(1,1,1,0.07)
261+
262+ component: menuData.icon ? icon : undefined
263+ Component {
264+ id: icon
265+ SettingsComponents.IconVisual {
266+ source: menuData.icon
267+ height: units.gu(3)
268+ width: height
269+ color: Theme.palette.selected.backgroundText
270+ }
271+ }
272+ }
273+ }
274+
242 Component {
275 Component {
243 id: checkableMenu;
276 id: checkableMenu;
244
277
@@ -664,7 +697,7 @@ Item {
664 Component {
697 Component {
665 id: buttonSectionMenu;
698 id: buttonSectionMenu;
666
699
667− ListItems.Standard {
700+ Menus.StandardMenu {
668 objectName: "buttonSectionMenu"
701 objectName: "buttonSectionMenu"
669 property QtObject menuData: null
702 property QtObject menuData: null
670 property var menuModel: menuFactory.menuModel
703 property var menuModel: menuFactory.menuModel
@@ -674,7 +707,7 @@ Item {
674 iconSource: menuData && menuData.icon || ""
707 iconSource: menuData && menuData.icon || ""
675 enabled: menuData && menuData.sensitive || false
708 enabled: menuData && menuData.sensitive || false
676 text: menuData && menuData.label || ""
709 text: menuData && menuData.label || ""
677− showDivider: false
710+ foregroundColor: Theme.palette.normal.backgroundText
678
711
679 onMenuModelChanged: {
712 onMenuModelChanged: {
680 loadAttributes();
713 loadAttributes();
@@ -687,11 +720,13 @@ Item {
687 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
720 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
688 }
721 }
689
722
723+ component: Component {
690− control: Button {
724+ Button {
691− text: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
725+ text: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
692
726
693− onClicked: {
727+ onClicked: {
694− menuModel.activate(menuIndex);
728+ menuModel.activate(menuIndex);
729+ }
695 }
730 }
696 }
731 }
697 }
732 }
@@ -712,6 +747,7 @@ Item {
712 if (component !== undefined) {
747 if (component !== undefined) {
713 return component;
748 return component;
714 }
749 }
750+ console.debug("Don't know how to make " + modelData.type + " for " + context);
715 }
751 }
716 if (modelData.isCheck || modelData.isRadio) {
752 if (modelData.isCheck || modelData.isRadio) {
717 return checkableMenu;
753 return checkableMenu;
qml/Panel/Indicators/MessageMenuItemFactory.qml+2−3
@@ -38,9 +38,8 @@ Item {
38 property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined)
38 property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined)
39
39
40 // TODO - bug #1260728
40 // TODO - bug #1260728
41− property var timeFormatter: Utils.TimeFormatter {
41+ property var timeFormatter: Utils.RelativeTimeFormatter {
42− time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
42+ time: getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000000
43− format: "hh:mm - MMM dd"
44 }
43 }
45
44
46 onMenuModelChanged: {
45 onMenuModelChanged: {
qml/Panel/MenuContent.qml+2
@@ -54,6 +54,7 @@ Rectangle {
54 id: listViewHeader
54 id: listViewHeader
55 objectName: "indicatorsListViewHeader"
55 objectName: "indicatorsListViewHeader"
56 model: content.indicatorsModel
56 model: content.indicatorsModel
57+ clip: true
57
58
58 anchors {
59 anchors {
59 left: parent.left
60 left: parent.left
@@ -99,6 +100,7 @@ Rectangle {
99 bottom: parent.bottom
100 bottom: parent.bottom
100 }
101 }
101 model: content.indicatorsModel
102 model: content.indicatorsModel
103+ clip: true
102
104
103 currentIndex: listViewHeader.currentIndex
105 currentIndex: listViewHeader.currentIndex
104 interactive: false
106 interactive: false