Merge lp:~nick-dedekind/ubuntu-settings-components/calendar-freeze into lp:ubuntu-settings-components

Proposed by Nick Dedekind
Status: Merged
Approved by: Michał Sawicz
Approved revision: 124
Merged at revision: 149
Proposed branch: lp:~nick-dedekind/ubuntu-settings-components/calendar-freeze
Merge into: lp:ubuntu-settings-components
Diff against target: 521 lines (+209/-154)
4 files modified
plugins/Ubuntu/Settings/Components/Calendar.js (+100/-0)
plugins/Ubuntu/Settings/Components/Calendar.qml (+104/-102)
plugins/Ubuntu/Settings/Components/dateExt.js (+0/-48)
tests/qmltests/Components/tst_Calendar.qml (+5/-4)
To merge this branch: bzr merge lp:~nick-dedekind/ubuntu-settings-components/calendar-freeze
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
PS Jenkins bot continuous-integration Pending
Lukáš Tinkl Pending
Review via email: mp+296297@code.launchpad.net

This proposal supersedes a proposal from 2016-03-30.

Commit message

Removed some of the timezone sensitive date code from calendar

Description of the change

Removed some of the timezone sensitive date code from calendar

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:124
https://unity8-jenkins.ubuntu.com/job/lp-ubuntu-settings-components-ci/28/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/1193
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1170
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1170
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1168
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1168/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1168
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1168/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1168
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1168/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1168
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1168/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1168
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1168/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1168
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1168/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-ubuntu-settings-components-ci/28/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

Works fine, no more freezes after changing TZ and triggering a redraw of the component.

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'plugins/Ubuntu/Settings/Components/Calendar.js'
2--- plugins/Ubuntu/Settings/Components/Calendar.js 1970-01-01 00:00:00 +0000
3+++ plugins/Ubuntu/Settings/Components/Calendar.js 2016-06-02 08:29:37 +0000
4@@ -0,0 +1,100 @@
5+.pragma library
6+.import "dateExt.js" as DateExt
7+
8+function Month(arg1, arg2) {
9+ if (arg1 === undefined) {
10+ var date = new Date();
11+ this.year = date.getFullYear();
12+ this.month = date.getMonth();
13+ }
14+ else if (arg1 !== undefined && arg2 === undefined) {
15+ this.year = arg1.year;
16+ this.month = arg1.month;
17+ } else {
18+ this.year = arg1;
19+ this.month = arg2;
20+ }
21+}
22+
23+Month.prototype.fromDate = function(date) {
24+ return new Month(date.getFullYear(), date.getMonth());
25+}
26+
27+Month.prototype.addMonths = function(months) {
28+ var date = new Date(this.year, this.month, 1).addMonths(months);
29+ return new Month(date.getFullYear(), date.getMonth());
30+}
31+
32+Month.prototype.toString = function() {
33+ return JSON.stringify(this);
34+}
35+
36+Month.prototype.valueOf = function() {
37+ return this.year * 12 + this.month;
38+}
39+
40+function Day(arg1, arg2, arg3) {
41+ if (arg1 === undefined) {
42+ var date = new Date();
43+ this.year = date.getFullYear();
44+ this.month = date.getMonth();
45+ this.day = date.getDate();
46+ }
47+ else if (arg1 !== undefined && arg2 === undefined) {
48+ this.year = arg1.year;
49+ this.month = arg1.month;
50+ this.day = arg1.day;
51+ } else {
52+ this.year = arg1;
53+ this.month = arg2;
54+ this.day = arg3;
55+ }
56+}
57+
58+Day.prototype.fromDate = function(date) {
59+ return new Day(date.getFullYear(), date.getMonth(), date.getDate());
60+}
61+
62+Day.prototype.addMonths = function(months) {
63+ var date = new Date(this.year, this.month, this.day).addMonths(months);
64+ return new Day(date.getFullYear(), date.getMonth(), date.getDate());
65+}
66+
67+Day.prototype.addDays = function(days) {
68+ var date = new Date(this.year, this.month, this.day).addDays(days);
69+ return new Day(date.getFullYear(), date.getMonth(), date.getDate());
70+}
71+
72+Day.prototype.dayofweek = function () /* 1 <= m <= 12, y > 1752 (in the U.K.) */
73+{
74+ var t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];
75+ var y = this.year;
76+ y = y - ((this.month+1) < 3 ? 1 : 0);
77+ return (y + y/4 - y/100 + y/400 + t[this.month] + this.day) % 7;
78+}
79+
80+Day.prototype.weekStart = function(weekStartDay) {
81+ var day = (new Date(this.year, this.month, this.day)).getDay(), n = 0
82+ while (day != weekStartDay) {
83+ if (day == 0) day = 6
84+ else day = day - 1
85+ n = n + 1
86+ }
87+ return this.addDays(-n)
88+}
89+
90+Day.prototype.valueOf = function() {
91+ // make sure there are no crossover values.
92+ return this.year * 373 + this.month * 31 + this.day;
93+}
94+
95+Day.prototype.toString = function() {
96+ return JSON.stringify(this);
97+}
98+
99+Day.prototype.equals = function(other) {
100+ if (other instanceof Day) {
101+ return other.valueOf() == this.valueOf();
102+ }
103+ return false;
104+}
105
106=== modified file 'plugins/Ubuntu/Settings/Components/Calendar.qml'
107--- plugins/Ubuntu/Settings/Components/Calendar.qml 2016-02-11 11:23:02 +0000
108+++ plugins/Ubuntu/Settings/Components/Calendar.qml 2016-06-02 08:29:37 +0000
109@@ -17,44 +17,31 @@
110 import QtQuick 2.4
111 import Ubuntu.Components 1.3
112 import "dateExt.js" as DateExt
113+import "Calendar.js" as Cal
114
115 ListView {
116 id: monthView
117
118 property bool collapsed: false
119- property var currentDate: selectedDate.monthStart().addDays(15)
120+ property var currentDate: new Date(priv.today.year, priv.today.month, 1)
121 property var firstDayOfWeek: Qt.locale(i18n.language).firstDayOfWeek
122 property var maximumDate
123 property var minimumDate
124- property var selectedDate: priv.today
125+ property var selectedDate: new Date(priv.today.year, priv.today.month, priv.today.day)
126+
127+ function reset() {
128+ if (!priv.ready) return;
129+ currentDate = new Date(priv.today.year, priv.today.month, 1)
130+ }
131
132 Component.onCompleted: {
133- priv.__populateModel()
134- timer.start()
135+ priv.__populateModel();
136 }
137
138 onCurrentIndexChanged: {
139- if (!priv.ready) return
140-
141- currentDate = currentItem.monthStart
142- }
143-
144- onCurrentDateChanged: {
145- if (!priv.ready) return
146-
147- priv.__populateModel();
148- }
149-
150- onMaximumDateChanged: {
151- if (!priv.ready) return
152-
153- priv.__populateModel()
154- }
155-
156- onMinimumDateChanged: {
157- if (!priv.ready) return
158-
159- priv.__populateModel()
160+ if (!priv.ready) return;
161+
162+ currentDate = new Date(currentItem.month.year, currentItem.month.month, 1);
163 }
164
165 ListModel {
166@@ -67,89 +54,107 @@
167 property bool ready: false
168 property int squareUnit: monthView.width / 7
169 property int verticalMargin: units.gu(1)
170- property var today: (new Date()).midnight()
171-
172- function __withinLowerMonthBound(date) {
173- return minimumDate == undefined || date.monthStart() >= minimumDate.monthStart()
174- }
175-
176- function __withinUpperMonthBound(date) {
177- return maximumDate == undefined || date.monthStart() <= maximumDate.monthStart()
178- }
179-
180- function __getRealMinimumDate(date) {
181- if (minimumDate != undefined && minimumDate > date) {
182- return minimumDate;
183- }
184- return date;
185- }
186-
187- function __getRealMaximumDate(date) {
188- if (maximumDate != undefined && maximumDate < date) {
189- return maximumDate;
190- }
191- return date;
192+ property var today: new Cal.Day().fromDate((new Date()))
193+
194+ property var currentMonth: new Cal.Month().fromDate(currentDate)
195+ property var selectedDay: new Cal.Day().fromDate(selectedDate)
196+ property var minimumMonth: minimumDate ? new Cal.Month().fromDate(minimumDate) : undefined
197+ property var maximumMonth: maximumDate ? new Cal.Month().fromDate(maximumDate) : undefined
198+
199+ property var minimumDay: minimumDate ? new Cal.Day().fromDate(minimumDate) : undefined
200+ property var maximumDay: maximumDate ? new Cal.Day().fromDate(maximumDate) : undefined
201+
202+ onCurrentMonthChanged: {
203+ if (!ready) return
204+ __populateModel();
205+ }
206+ onSelectedDayChanged: {
207+ if (!ready) return
208+ __populateModel();
209+ }
210+ onMinimumMonthChanged: {
211+ if (!ready) return
212+ __populateModel();
213+ }
214+ onMaximumMonthChanged: {
215+ if (!ready) return
216+ __populateModel();
217+ }
218+
219+ function __getRealMinimumMonth(month) {
220+ if (minimumMonth !== undefined && minimumMonth > month) {
221+ return minimumMonth;
222+ }
223+ return month;
224+ }
225+
226+ function __getRealMaximumMonth(date) {
227+ if (maximumMonth !== undefined && maximumMonth < month) {
228+ return maximumMonth;
229+ }
230+ return month;
231 }
232
233 function __populateModel() {
234 // disable the onCurrentIndexChanged logic
235- priv.ready = false
236+ priv.ready = false;
237
238- var minimumAddedDate = priv.__getRealMinimumDate(currentDate.addMonths(-2)).monthStart();
239- var maximumAddedDate = priv.__getRealMaximumDate(currentDate.addMonths(2)).monthStart();
240+ var minimumMonth = __getRealMinimumMonth(currentMonth).addMonths(-2);
241+ var maximumMonth = __getRealMinimumMonth(currentMonth).addMonths(2);
242
243 // Remove old minimum months
244- while (calendarModel.count > 0 && calendarModel.get(0).monthStart < minimumAddedDate) {
245+ while (calendarModel.count > 0 && new Cal.Month(calendarModel.get(0).month) < minimumMonth) {
246 calendarModel.remove(0);
247 }
248 // Remove old maximum months
249- while (calendarModel.count > 0 && calendarModel.get(calendarModel.count - 1).monthStart > maximumAddedDate) {
250+ while (calendarModel.count > 0 && new Cal.Month(calendarModel.get(calendarModel.count - 1).month) > maximumMonth) {
251 calendarModel.remove(calendarModel.count - 1);
252 }
253
254- // Add new months
255- var i = 0;
256- while (calendarModel.count > 0 && calendarModel.get(0).monthStart > minimumAddedDate) {
257- calendarModel.insert(0, { "monthStart": calendarModel.get(0).monthStart.addMonths(-1) });
258- ++i;
259- }
260-
261 if (calendarModel.count > 0) {
262- i = 0;
263- while (calendarModel.count > 0 && calendarModel.get(calendarModel.count - 1).monthStart < maximumAddedDate) {
264- calendarModel.append({ "monthStart": calendarModel.get(calendarModel.count - 1).monthStart.addMonths(1) });
265- ++i;
266+ // Add new months
267+ var firstMonth = new Cal.Month(calendarModel.get(0).month);
268+ while (firstMonth > minimumMonth) {
269+ calendarModel.insert(0, { "month": firstMonth.addMonths(-1) });
270+ firstMonth = new Cal.Month(calendarModel.get(0).month);
271+ }
272+
273+ var lastMonth = new Cal.Month(calendarModel.get(calendarModel.count - 1).month);
274+ while (lastMonth < maximumMonth) {
275+ calendarModel.append({ "month": lastMonth.addMonths(1) });
276+ lastMonth = new Cal.Month(calendarModel.get(calendarModel.count - 1).month);
277 }
278 } else {
279- i = 0;
280+ var i = 0;
281 do {
282- calendarModel.append({ "monthStart": minimumAddedDate.addMonths(i) });
283+ calendarModel.append({ "month": minimumMonth.addMonths(i) });
284 ++i;
285- } while (calendarModel.get(i-1).monthStart < maximumAddedDate)
286+ } while (minimumMonth.addMonths(i) <= maximumMonth)
287 }
288
289- currentIndex = DateExt.diffMonths(minimumAddedDate, currentDate);
290+ currentIndex = currentMonth - minimumMonth;
291
292 // Ok, we're all set up. enable the onCurrentIndexChanged logic
293 priv.ready = true
294 }
295 }
296
297- Timer {
298- id: timer
299- interval: 60000
300- repeat: true
301- running: true
302- triggeredOnStart: true
303-
304- onTriggered: priv.today = (new Date()).midnight()
305+ LiveTimer {
306+ frequency: LiveTimer.Minute
307+ onTrigger: {
308+ var today = new Cal.Day().fromDate((new Date()));
309+ if (!priv.today.equals(today)) {
310+ priv.today = today;
311+ reset();
312+ }
313+ }
314 }
315
316 width: parent.width
317 height: priv.squareUnit * (collapsed ? 1 : 6) + priv.verticalMargin * 2
318 interactive: !collapsed
319 clip: true
320- cacheBuffer: Math.max(width + 1, 0)
321+ cacheBuffer: Math.max((width+1) * 3, 0) // one page left, one page right
322 highlightRangeMode: ListView.StrictlyEnforceRange
323 preferredHighlightBegin: 0
324 preferredHighlightEnd: width
325@@ -157,6 +162,7 @@
326 orientation: ListView.Horizontal
327 snapMode: ListView.SnapOneItem
328 focus: true
329+ highlightFollowsCurrentItem: true
330
331 Keys.onLeftPressed: selectedDate.addDays(-1)
332 Keys.onRightPressed: selectedDate.addDays(1)
333@@ -164,10 +170,12 @@
334 delegate: Item {
335 id: monthItem
336
337- property int currentWeekRow: Math.floor((selectedDate.getTime() - gridStart.getTime()) / Date.msPerWeek)
338+ property int currentWeekRow: Math.floor((priv.selectedDay - gridStart) / 7)
339 property var gridStart: monthStart.weekStart(firstDayOfWeek)
340 property var monthEnd: monthStart.addMonths(1)
341- property var monthStart: model.monthStart
342+ property var monthStart: new Cal.Day(model.month.year, model.month.month, 1)
343+
344+ property var month: new Cal.Month(model.month)
345
346 width: monthView.width
347 height: monthView.height
348@@ -187,33 +195,23 @@
349 id: dayItem
350 objectName: "dayItem" + index
351
352- property bool isCurrent: (dayStart.getFullYear() == selectedDate.getFullYear() &&
353- dayStart.getMonth() == selectedDate.getMonth() &&
354- dayStart.getDate() == selectedDate.getDate())
355- property bool isCurrentMonth: monthStart <= dayStart && dayStart < monthEnd
356+ property bool isCurrent: dayStart.equals(priv.selectedDay)
357+ property bool isCurrentMonth: (monthStart < dayStart || monthStart.equals(dayStart)) && dayStart < monthEnd
358 property bool isCurrentWeek: row == currentWeekRow
359 property bool isSunday: weekday == 0
360- property bool isToday: dayStart.getTime() == priv.today.getTime()
361- property bool isWithinBounds: (minimumDate == undefined || dayStart >= minimumDate) &&
362- (maximumDate == undefined || dayStart <= maximumDate)
363+ property bool isToday: dayStart.equals(priv.today)
364+ property bool isWithinBounds: (priv.minimumDay === undefined || dayStart >= priv.minimumDay) &&
365+ (priv.maximumDay === undefined || dayStart <= priv.maximumDay)
366 property int row: Math.floor(index / 7)
367 property int weekday: (index % 7 + firstDayOfWeek) % 7
368 property real bottomMargin: (row == 5 || (collapsed && isCurrentWeek)) ? -priv.verticalMargin : 0
369 property real topMargin: (row == 0 || (collapsed && isCurrentWeek)) ? -priv.verticalMargin : 0
370 property var dayStart: gridStart.addDays(index)
371
372- // Styling properties
373- property color color: theme.palette.normal.backgroundText
374- property color todayColor: theme.palette.normal.positive
375- property string fontSize: "large"
376- property var backgroundColor: "transparent" // FIXME use color instead var when Qt will fix the bug with the binding (loses alpha)
377- property var sundayBackgroundColor: "#19AEA79F" // FIXME use color instead var when Qt will fix the bug with the binding (loses alpha)
378-
379 visible: collapsed ? isCurrentWeek : true
380 width: priv.squareUnit
381 height: priv.squareUnit
382
383-// ItemStyle.class: "day"
384 Item {
385 anchors {
386 fill: parent
387@@ -223,19 +221,21 @@
388
389 Rectangle {
390 anchors.fill: parent
391- visible: color.a > 0
392- color: isSunday ? dayItem.sundayBackgroundColor : dayItem.backgroundColor
393+ visible: isSunday
394+ opacity: 0.1
395+ color: UbuntuColors.warmGrey
396 }
397
398 Label {
399 anchors.centerIn: parent
400- text: dayStart.getDate()
401- fontSize: dayItem.fontSize
402- color: isToday ? dayItem.todayColor : dayItem.color
403- scale: isCurrent ? 1.8 : 1.
404- opacity: isWithinBounds ? isCurrentMonth ? 1. : 0.3 : 0.1
405+ text: dayStart.day
406+ font.pixelSize: units.dp(isCurrent ? 36 : 20)
407+ color: isCurrentMonth && isWithinBounds ? isToday ? UbuntuColors.green :
408+ theme.palette.normal.backgroundText :
409+ theme.palette.disabled.backgroundText
410+ opacity: isWithinBounds ? 1. : 0.33
411
412- Behavior on scale {
413+ Behavior on font.pixelSize {
414 NumberAnimation { duration: 50 }
415 }
416 }
417@@ -248,7 +248,9 @@
418 bottomMargin: dayItem.bottomMargin
419 }
420
421- onReleased: if (isWithinBounds) monthView.selectedDate = dayStart
422+ onClicked: {
423+ if (isWithinBounds) monthView.selectedDate = new Date(dayStart.year, dayStart.month, dayStart.day)
424+ }
425 }
426 }
427 }
428
429=== modified file 'plugins/Ubuntu/Settings/Components/dateExt.js'
430--- plugins/Ubuntu/Settings/Components/dateExt.js 2013-10-29 22:08:08 +0000
431+++ plugins/Ubuntu/Settings/Components/dateExt.js 2016-06-02 08:29:37 +0000
432@@ -22,21 +22,6 @@
433 ][month] + (month == 1) * Date.leapYear(year)
434 }
435
436-Date.weeksInMonth = function(year, month, weekday) {
437- var y = year, m = month
438- var date0 = new Date(y, m, 1)
439- var date1 = new Date(y + (m == 11), m < 11 ? m + 1 : 0, 1)
440- var day = date0.getDay()
441- var m = (date1.getTime() - date0.getTime()) / Date.msPerDay
442- var n = 0
443- while (m > 0) {
444- if (day == weekday) n = n + 1
445- day = day < 6 ? day + 1 : 0
446- m = m - 1
447- }
448- return n
449-}
450-
451 Date.prototype.midnight = function() {
452 var date = new Date(this)
453 date.setHours(0,0,0,0);
454@@ -54,36 +39,3 @@
455 date.setMonth(date.getMonth() + months)
456 return date
457 }
458-
459-Date.prototype.weekStart = function(weekStartDay) {
460- var date = this.midnight()
461- var day = date.getDay(), n = 0
462- while (day != weekStartDay) {
463- if (day == 0) day = 6
464- else day = day - 1
465- n = n + 1
466- }
467- return date.addDays(-n)
468-}
469-
470-Date.prototype.monthStart = function() {
471- var date = new Date(this).midnight();
472- date.setDate(1);
473- return date;
474-}
475-
476-Date.prototype.weekNumber = function() {
477- var date = this.weekStart(1).addDays(3) // Thursday midnight
478- var newYear = new Date(date.getFullYear(), 0 /*Jan*/, 1 /*the 1st*/)
479- var n = 0
480- var tx = date.getTime(), tn = newYear.getTime()
481- while (tn < tx) {
482- tx = tx - Date.msPerWeek
483- n = n + 1
484- }
485- return n
486-}
487-
488-Date.prototype.weeksInMonth = function(weekday) {
489- return Date.weeksInMonth(this.getFullYear(), this.getMonth(), weekday)
490-}
491
492=== modified file 'tests/qmltests/Components/tst_Calendar.qml'
493--- tests/qmltests/Components/tst_Calendar.qml 2016-02-11 11:23:02 +0000
494+++ tests/qmltests/Components/tst_Calendar.qml 2016-06-02 08:29:37 +0000
495@@ -20,12 +20,15 @@
496 import QtTest 1.0
497 import Ubuntu.Test 0.1
498 import Ubuntu.Settings.Components 0.1
499+import Ubuntu.Components 1.3
500
501-Item {
502+Rectangle {
503 width: units.gu(42)
504 height: units.gu(75)
505
506- Text {
507+ color: theme.palette.normal.background
508+
509+ Label {
510 id: label
511 anchors {
512 left: parent.left
513@@ -44,8 +47,6 @@
514 right: parent.right
515 top: label.bottom
516 }
517-
518- selectedDate: new Date()
519 }
520
521 UbuntuTestCase {

Subscribers

People subscribed via source and target branches

to all changes: