Merge lp:~nik90/ubuntu-clock-app/13-next-alarm-bottomedge into lp:ubuntu-clock-app

Proposed by Nekhelesh Ramananthan
Status: Superseded
Proposed branch: lp:~nik90/ubuntu-clock-app/13-next-alarm-bottomedge
Merge into: lp:ubuntu-clock-app
Diff against target: 1034 lines (+355/-290)
14 files modified
app/alarm/AlarmDelegate.qml (+7/-31)
app/alarm/AlarmList.qml (+2/-5)
app/alarm/AlarmPage.qml (+4/-1)
app/alarm/AlarmUtils.qml (+98/-15)
app/alarm/EditAlarmPage.qml (+1/-2)
app/clock/ClockPage.qml (+20/-4)
app/clock/MainClock.qml (+0/-39)
app/components/Clock.qml (+1/-1)
app/components/Utils.js (+0/-25)
app/ubuntu-clock-app.qml (+36/-11)
app/upstreamcomponents/PageWithBottomEdge.qml (+167/-154)
app/worldclock/UserWorldCityList.qml (+0/-2)
tests/autopilot/ubuntu_clock_app/emulators.py (+2/-0)
tests/unit/tst_alarm.qml (+17/-0)
To merge this branch: bzr merge lp:~nik90/ubuntu-clock-app/13-next-alarm-bottomedge
Reviewer Review Type Date Requested Status
Ubuntu Clock Developers Pending
Review via email: mp+237187@code.launchpad.net

This proposal has been superseded by a proposal from 2014-10-05.

Commit message

Dynamically sets the bottom edge title with the time to the next active alarm.

Description of the change

Dynamically sets the bottom edge title with the time to the next active alarm.

To post a comment you must log in.
110. By Nekhelesh Ramananthan

Fixed failing qml tests

111. By Nekhelesh Ramananthan

merged pre-requisite branch changes

112. By Nekhelesh Ramananthan

Added unit tests for bottom edge title

113. By Nekhelesh Ramananthan

Split qml unit test into smaller unit test for better debugging when a test fails

114. By Nekhelesh Ramananthan

Merged pre-requisite branch changes

115. By Nekhelesh Ramananthan

merged prerequisite branch

116. By Nekhelesh Ramananthan

updated changelog

117. By Nekhelesh Ramananthan

Updated if loop according to riccardo's suggestion

118. By Nekhelesh Ramananthan

merged prerequisite branch

119. By Nekhelesh Ramananthan

Fixed AP test

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'app/alarm/AlarmDelegate.qml'
--- app/alarm/AlarmDelegate.qml 2014-09-03 22:51:48 +0000
+++ app/alarm/AlarmDelegate.qml 2014-10-05 15:35:22 +0000
@@ -23,6 +23,8 @@
23ListItemWithActions {23ListItemWithActions {
24 id: root24 id: root
2525
26 property var localTime
27
26 width: parent ? parent.width : 028 width: parent ? parent.width : 0
27 height: units.gu(6)29 height: units.gu(6)
28 color: "Transparent"30 color: "Transparent"
@@ -39,6 +41,7 @@
3941
40 fontSize: "medium"42 fontSize: "medium"
41 text: Qt.formatTime(date)43 text: Qt.formatTime(date)
44 opacity: model.enabled ? 1.0 : 0.8
42 }45 }
4346
44 Column {47 Column {
@@ -70,9 +73,9 @@
7073
71 fontSize: "xx-small"74 fontSize: "xx-small"
72 width: parent.width75 width: parent.width
73 visible: type === Alarm.Repeating || _internalTimerLoader.sourceComponent != undefined
74 wrapMode: Text.WrapAtWordBoundaryOrAnywhere76 wrapMode: Text.WrapAtWordBoundaryOrAnywhere
75 text: alarmUtils.format_day_string(daysOfWeek, type)77 text: type === Alarm.Repeating ? alarmUtils.format_day_string(daysOfWeek, type)
78 : alarmUtils.get_time_to_next_alarm(model.date - localTime)
76 }79 }
77 }80 }
7881
@@ -126,35 +129,8 @@
126 if (model.status === Alarm.Ready) {129 if (model.status === Alarm.Ready) {
127 alarmStatus.checked = model.enabled;130 alarmStatus.checked = model.enabled;
128131
129 if(alarmStatus.checked) {132 if(alarmStatus.checked && type === Alarm.Repeating) {
130 var timeObject = alarmUtils.get_time_to_next_alarm(model.date - new Date())133 alarmSubtitle.text = alarmUtils.get_time_to_next_alarm(model.date - localTime)
131 var alarmETA
132
133 // TRANSLATORS: the first argument is the number of days,
134 // followed by hour and minute (eg. in 1d 20h 3m)
135 if(timeObject.days) {
136 alarmETA = i18n.tr("in %1d %1h %2m")
137 .arg(timeObject.days)
138 .arg(timeObject.hours)
139 .arg(timeObject.minutes)
140 }
141
142 // TRANSLATORS: the first argument is the number of
143 // hours followed by the minutes (eg. in 4h 3m)
144 else if (timeObject.hours) {
145 alarmETA = i18n.tr("in %1h %2m")
146 .arg(timeObject.hours)
147 .arg(timeObject.minutes)
148 }
149
150 // TRANSLATORS: the argument is the number of
151 // minutes to the alarm (eg. in 3m)
152 else {
153 alarmETA = i18n.tr("in %1m")
154 .arg(timeObject.minutes)
155 }
156
157 alarmSubtitle.text = alarmETA
158 _internalTimerLoader.sourceComponent = _internalTimerComponent134 _internalTimerLoader.sourceComponent = _internalTimerComponent
159 }135 }
160 }136 }
161137
=== modified file 'app/alarm/AlarmList.qml'
--- app/alarm/AlarmList.qml 2014-09-25 11:26:43 +0000
+++ app/alarm/AlarmList.qml 2014-10-05 15:35:22 +0000
@@ -21,13 +21,13 @@
21import Ubuntu.Components.ListItems 1.0 as ListItem21import Ubuntu.Components.ListItems 1.0 as ListItem
22import "../components"22import "../components"
23import "../upstreamcomponents"23import "../upstreamcomponents"
24import "../components/Utils.js" as Utils
2524
26MultipleSelectionListView {25MultipleSelectionListView {
27 id: alarmListView26 id: alarmListView
28 objectName: "alarmListView"27 objectName: "alarmListView"
2928
30 property var _currentSwipedItem: null29 property var _currentSwipedItem: null
30 property var localTime
3131
32 function _updateSwipeState(item)32 function _updateSwipeState(item)
33 {33 {
@@ -51,15 +51,12 @@
51 clip: true51 clip: true
52 anchors.fill: parent52 anchors.fill: parent
5353
54 AlarmUtils {
55 id: alarmUtils
56 }
57
58 listDelegate: AlarmDelegate {54 listDelegate: AlarmDelegate {
59 id: alarmDelegate55 id: alarmDelegate
60 objectName: "alarm" + index56 objectName: "alarm" + index
6157
62 property var removalAnimation58 property var removalAnimation
59 localTime: alarmListView.localTime
6360
64 function remove() {61 function remove() {
65 removalAnimation.start()62 removalAnimation.start()
6663
=== modified file 'app/alarm/AlarmPage.qml'
--- app/alarm/AlarmPage.qml 2014-09-26 12:24:11 +0000
+++ app/alarm/AlarmPage.qml 2014-10-05 15:35:22 +0000
@@ -23,10 +23,12 @@
23Page {23Page {
24 id: alarmPage24 id: alarmPage
2525
26 property var alarmModel
27
26 title: i18n.tr("Alarms")28 title: i18n.tr("Alarms")
27 objectName: 'AlarmPage'29 objectName: 'AlarmPage'
2830
29 Component.onCompleted: console.log("Alarm Page loaded")31 Component.onCompleted: console.log("[LOG]: Alarm Page loaded")
3032
31 flickable: null33 flickable: null
3234
@@ -127,6 +129,7 @@
127 id: alarmListView129 id: alarmListView
128 listModel: alarmModel130 listModel: alarmModel
129 anchors.fill: parent131 anchors.fill: parent
132 localTime: clockTime
130 }133 }
131134
132 EmptyState {135 EmptyState {
133136
=== modified file 'app/alarm/AlarmUtils.qml'
--- app/alarm/AlarmUtils.qml 2014-09-03 22:36:07 +0000
+++ app/alarm/AlarmUtils.qml 2014-10-05 15:35:22 +0000
@@ -50,21 +50,65 @@
50 }50 }
51 }51 }
5252
53 function get_time_to_next_alarm ( datetime_offset ) {53 // Function to set the bottom edge title with "Next Active in..."
54 // increase by a minute, so we could make a nicer time54 function set_bottom_edge_title(alarmModel, clockTime) {
55 // to the next alarm, otherwise a minute always missing55 var bottom_edge_title = i18n.tr("No active alarms")
56 // which makes it look odd56
57 datetime_offset += 60000;57 /*
5858 Check if alarm model received is valid and has saved alarms and only
59 var days_in_offset = Math.floor( datetime_offset / ( 3600000 * 24 ) );59 then proceed to find the next active alarm.
60 var hours_in_offset = Math.floor( datetime_offset / 3600000 % 24 );60 */
61 var minutes_in_offset = Math.floor( datetime_offset / 60000 % 60 );61 if (alarmModel && alarmModel.count) {
6262 var activeAlarmDate = _get_next_active_alarm(alarmModel, clockTime)
63 return {63
64 days : days_in_offset,64 // Return immediately if there are no active alarms found
65 hours : hours_in_offset,65 if (!activeAlarmDate) {
66 minutes : minutes_in_offset66 return bottom_edge_title
67 }67 }
68 }
69
70 else {
71 return bottom_edge_title
72 }
73
74 bottom_edge_title = i18n.tr("Next Alarm %1").arg(get_time_to_next_alarm(activeAlarmDate - clockTime))
75 return bottom_edge_title
76 }
77
78 // Function to format the time to next alarm into a string
79 function get_time_to_next_alarm(totalTime) {
80 if(totalTime < 0) {
81 return i18n.tr("Alarm Passed")
82 }
83
84 var timeObject = _split_time(totalTime);
85 var alarmETA
86
87 // TRANSLATORS: the first argument is the number of days,
88 // followed by hour and minute (eg. in 1d 20h 3m)
89 if(timeObject.days) {
90 alarmETA = i18n.tr("in %1d %2h %3m")
91 .arg(timeObject.days)
92 .arg(timeObject.hours)
93 .arg(timeObject.minutes)
94 }
95
96 // TRANSLATORS: the first argument is the number of
97 // hours followed by the minutes (eg. in 4h 3m)
98 else if (timeObject.hours) {
99 alarmETA = i18n.tr("in %1h %2m")
100 .arg(timeObject.hours)
101 .arg(timeObject.minutes)
102 }
103
104 // TRANSLATORS: the argument is the number of
105 // minutes to the alarm (eg. in 3m)
106 else {
107 alarmETA = i18n.tr("in %1m")
108 .arg(timeObject.minutes)
109 }
110
111 return alarmETA;
68 }112 }
69113
70 // Function return the alarm dayOfWeek according to the day provided114 // Function return the alarm dayOfWeek according to the day provided
@@ -84,6 +128,45 @@
84 INTERNAL FUNCTIONS128 INTERNAL FUNCTIONS
85 */129 */
86130
131 /*
132 Function to get the next active alarm. This function ignores alarms in the
133 past and also iteratively looks through every alarm since the alarm model
134 does not always list the active alarms in chronological order.
135 */
136 function _get_next_active_alarm(alarmModel, clockTime) {
137 var activeAlarmDate = undefined
138
139 for (var i=0; i<alarmModel.count; i++) {
140 var currentAlarm = alarmModel.get(i)
141 if (currentAlarm.enabled && currentAlarm.date > clockTime) {
142 if (activeAlarmDate === undefined ||
143 currentAlarm.date < activeAlarmDate) {
144 activeAlarmDate = currentAlarm.date
145 }
146 }
147 }
148
149 return activeAlarmDate
150 }
151
152 // Function to split time (in ms) into days, hours and minutes
153 function _split_time(totalTime) {
154 // increase by a minute, so we could make a nicer time
155 // to the next alarm, otherwise a minute always missing
156 // which makes it look odd
157 totalTime += 60000;
158
159 var days_in_offset = Math.floor(totalTime / ( 3600000 * 24));
160 var hours_in_offset = Math.floor(totalTime / 3600000 % 24);
161 var minutes_in_offset = Math.floor(totalTime / 60000 % 60);
162
163 return {
164 days : days_in_offset,
165 hours : hours_in_offset,
166 minutes : minutes_in_offset
167 }
168 }
169
87 // Function to determine the locale's weekdays value170 // Function to determine the locale's weekdays value
88 function _get_weekdays() {171 function _get_weekdays() {
89 var weekDays = 0172 var weekDays = 0
90173
=== modified file 'app/alarm/EditAlarmPage.qml'
--- app/alarm/EditAlarmPage.qml 2014-09-25 11:26:43 +0000
+++ app/alarm/EditAlarmPage.qml 2014-10-05 15:35:22 +0000
@@ -23,7 +23,6 @@
23import Ubuntu.Components.Pickers 1.023import Ubuntu.Components.Pickers 1.0
24import Ubuntu.Components.ListItems 1.0 as ListItem24import Ubuntu.Components.ListItems 1.0 as ListItem
25import "../components"25import "../components"
26import "../components/Utils.js" as Utils
2726
28Page {27Page {
29 id: _addAlarmPage28 id: _addAlarmPage
@@ -177,7 +176,7 @@
177176
178 onErrorChanged: {177 onErrorChanged: {
179 if (error !== Alarm.NoError) {178 if (error !== Alarm.NoError) {
180 Utils.log(debugMode, "Error saving alarm, code: " + error)179 console.log("[LOG]: Error saving alarm, code: " + error)
181 }180 }
182 }181 }
183182
184183
=== modified file 'app/clock/ClockPage.qml'
--- app/clock/ClockPage.qml 2014-09-26 11:36:12 +0000
+++ app/clock/ClockPage.qml 2014-10-05 15:35:22 +0000
@@ -17,12 +17,11 @@
17 */17 */
1818
19import QtQuick 2.319import QtQuick 2.3
20import U1db 1.0 as U1db
21import Ubuntu.Components 1.120import Ubuntu.Components 1.1
21import "../alarm"
22import "../components"22import "../components"
23import "../upstreamcomponents"23import "../upstreamcomponents"
24import "../worldclock"24import "../worldclock"
25import "../components/Utils.js" as Utils
2625
27PageWithBottomEdge {26PageWithBottomEdge {
28 id: _clockPage27 id: _clockPage
@@ -31,15 +30,32 @@
31 // Property to keep track of the clock mode30 // Property to keep track of the clock mode
32 property alias isDigital: clock.isDigital31 property alias isDigital: clock.isDigital
3332
33 // Property to keep track of the clock time
34 property alias clockTime: clock.analogTime
35
36 property var alarmModel
37
34 flickable: null38 flickable: null
3539 bottomEdgeTitle: alarmUtils.set_bottom_edge_title(alarmModel, clockTime)
36 Component.onCompleted: Utils.log(debugMode, "Clock Page loaded")40
41 Component.onCompleted: {
42 console.log("[LOG]: Clock Page loaded")
43 _clockPage.setBottomEdgePage(Qt.resolvedUrl("../alarm/AlarmPage.qml"), { alarmModel: alarmModel })
44 }
45
46 AlarmUtils {
47 id: alarmUtils
48 }
3749
38 Flickable {50 Flickable {
39 id: _flickable51 id: _flickable
4052
41 Component.onCompleted: otherElementsStartUpAnimation.start()53 Component.onCompleted: otherElementsStartUpAnimation.start()
4254
55 onFlickStarted: {
56 forceActiveFocus()
57 }
58
43 anchors.fill: parent59 anchors.fill: parent
44 contentWidth: parent.width60 contentWidth: parent.width
45 contentHeight: clock.height + date.height + locationRow.height61 contentHeight: clock.height + date.height + locationRow.height
4662
=== modified file 'app/clock/MainClock.qml'
--- app/clock/MainClock.qml 2014-08-24 12:47:50 +0000
+++ app/clock/MainClock.qml 2014-10-05 15:35:22 +0000
@@ -17,7 +17,6 @@
17 */17 */
1818
19import QtQuick 2.319import QtQuick 2.3
20import DateTime 1.0
21import Ubuntu.Components 1.120import Ubuntu.Components 1.1
22import "../components"21import "../components"
2322
@@ -30,44 +29,6 @@
3029
31 isMainClock: true30 isMainClock: true
3231
33 Connections {
34 target: clockApp
35 onApplicationStateChanged: {
36 localTimeSource.update()
37 }
38 }
39
40 DateTime {
41 id: localTimeSource
42 updateInterval: isDigital ? 1000 : 10
43 }
44
45 /*
46 Create a new Date() object and pass the date, month, year, hour, minute
47 and second received from the DateTime plugin manually to ensure the
48 timezone info is set correctly.
49
50 Javascript Month is 0-11 while QDateTime month is 1-12. Hence the -1
51 is required.
52 */
53
54 /*
55 FIXME: When the upstream QT bug at
56 https://bugreports.qt-project.org/browse/QTBUG-40275 is fixed it will be
57 possible to receive a datetime object directly instead of using this hack.
58 */
59 analogTime: new Date
60 (
61 localTimeSource.localDateString.split(":")[0],
62 localTimeSource.localDateString.split(":")[1]-1,
63 localTimeSource.localDateString.split(":")[2],
64 localTimeSource.localTimeString.split(":")[0],
65 localTimeSource.localTimeString.split(":")[1],
66 localTimeSource.localTimeString.split(":")[2],
67 localTimeSource.localTimeString.split(":")[3]
68 )
69 time: Qt.formatTime(analogTime)
70
71 isDigital: clockModeDocument.contents.digitalMode ? true : false32 isDigital: clockModeDocument.contents.digitalMode ? true : false
7233
73 Component.onCompleted: {34 Component.onCompleted: {
7435
=== modified file 'app/components/Clock.qml'
--- app/components/Clock.qml 2014-09-06 15:16:43 +0000
+++ app/components/Clock.qml 2014-10-05 15:35:22 +0000
@@ -18,7 +18,6 @@
1818
19import QtQuick 2.319import QtQuick 2.3
20import Ubuntu.Components 1.120import Ubuntu.Components 1.1
21import "Utils.js" as Utils
2221
23/*22/*
24 Generic clock component which has a digital and analog mode. A flip animation23 Generic clock component which has a digital and analog mode. A flip animation
@@ -148,6 +147,7 @@
148 enabled: isMainClock147 enabled: isMainClock
149 anchors.fill: parent148 anchors.fill: parent
150 onClicked: {149 onClicked: {
150 forceActiveFocus()
151 clockFlipAnimation.start()151 clockFlipAnimation.start()
152 }152 }
153 }153 }
154154
=== removed file 'app/components/Utils.js'
--- app/components/Utils.js 2014-07-17 12:21:45 +0000
+++ app/components/Utils.js 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd
3 *
4 * This file is part of Ubuntu Clock App
5 *
6 * Ubuntu Clock App is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3 as
8 * published by the Free Software Foundation.
9 *
10 * Ubuntu Clock App is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19.pragma library
20
21function log (debugMode, message) {
22 if (debugMode) {
23 console.log("[LOG]" + message)
24 }
25}
260
=== modified file 'app/ubuntu-clock-app.qml'
--- app/ubuntu-clock-app.qml 2014-08-26 20:20:37 +0000
+++ app/ubuntu-clock-app.qml 2014-10-05 15:35:22 +0000
@@ -17,12 +17,11 @@
17 */17 */
1818
19import QtQuick 2.319import QtQuick 2.3
20import DateTime 1.0
20import U1db 1.0 as U1db21import U1db 1.0 as U1db
21import Ubuntu.Components 1.122import Ubuntu.Components 1.1
22import "clock"23import "clock"
23import "alarm"
24import "components"24import "components"
25import "components/Utils.js" as Utils
2625
27MainView {26MainView {
28 id: clockApp27 id: clockApp
@@ -30,9 +29,6 @@
30 // Property to store the state of an application (active or suspended)29 // Property to store the state of an application (active or suspended)
31 property bool applicationState: Qt.application.active30 property bool applicationState: Qt.application.active
3231
33 // Property to enable/disable the debug mode to show more console output
34 property bool debugMode: true
35
36 // objectName for functional testing purposes (autopilot-qt5)32 // objectName for functional testing purposes (autopilot-qt5)
37 objectName: "clock"33 objectName: "clock"
3834
@@ -77,7 +73,16 @@
7773
78 AlarmModel {74 AlarmModel {
79 id: alarmModel75 id: alarmModel
80 Component.onCompleted: Utils.log(debugMode, "Alarm Database loaded")76 Component.onCompleted: console.log("[LOG]: Alarm Database loaded")
77 }
78
79 DateTime {
80 id: localTimeSource
81 updateInterval: clockModeDocument.contents.digitalMode ? 1000 : 10
82 }
83
84 onApplicationStateChanged: {
85 localTimeSource.update()
81 }86 }
8287
83 PageStack {88 PageStack {
@@ -97,11 +102,31 @@
97 */102 */
98103
99 /*104 /*
100 #TODO: The bottom edge title should reflect the time to the next105 Create a new Date() object and pass the date, month, year, hour, minute
101 alarm. For instance it should read "Next alarm in 9h23m".106 and second received from the DateTime plugin manually to ensure the
102 */107 timezone info is set correctly.
103 bottomEdgeTitle: i18n.tr("Alarms")108
104 bottomEdgePageComponent: AlarmPage {}109 Javascript Month is 0-11 while QDateTime month is 1-12. Hence the -1
110 is required.
111 */
112
113 /*
114 FIXME: When the upstream QT bug at
115 https://bugreports.qt-project.org/browse/QTBUG-40275 is fixed it will be
116 possible to receive a datetime object directly instead of using this hack.
117 */
118
119 alarmModel: alarmModel
120 clockTime: new Date
121 (
122 localTimeSource.localDateString.split(":")[0],
123 localTimeSource.localDateString.split(":")[1]-1,
124 localTimeSource.localDateString.split(":")[2],
125 localTimeSource.localTimeString.split(":")[0],
126 localTimeSource.localTimeString.split(":")[1],
127 localTimeSource.localTimeString.split(":")[2],
128 localTimeSource.localTimeString.split(":")[3]
129 )
105 }130 }
106 }131 }
107}132}
108133
=== modified file 'app/upstreamcomponents/PageWithBottomEdge.qml'
--- app/upstreamcomponents/PageWithBottomEdge.qml 2014-09-20 10:47:21 +0000
+++ app/upstreamcomponents/PageWithBottomEdge.qml 2014-10-05 15:35:22 +0000
@@ -62,7 +62,7 @@
6262
63*/63*/
6464
65import QtQuick 2.365import QtQuick 2.2
66import Ubuntu.Components 1.166import Ubuntu.Components 1.1
6767
68Page {68Page {
@@ -71,7 +71,7 @@
71 property alias bottomEdgePageComponent: edgeLoader.sourceComponent71 property alias bottomEdgePageComponent: edgeLoader.sourceComponent
72 property alias bottomEdgePageSource: edgeLoader.source72 property alias bottomEdgePageSource: edgeLoader.source
73 property alias bottomEdgeTitle: tipLabel.text73 property alias bottomEdgeTitle: tipLabel.text
74 property alias bottomEdgeEnabled: bottomEdge.visible74 property bool bottomEdgeEnabled: true
75 property int bottomEdgeExpandThreshold: page.height * 0.275 property int bottomEdgeExpandThreshold: page.height * 0.2
76 property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded76 property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
77 property bool reloadBottomEdgePage: true77 property bool reloadBottomEdgePage: true
@@ -87,6 +87,9 @@
87 signal bottomEdgeReleased()87 signal bottomEdgeReleased()
88 signal bottomEdgeDismissed()88 signal bottomEdgeDismissed()
8989
90 function giveFocus() {
91 tip.forceActiveFocus()
92 }
9093
91 function showBottomEdgePage(source, properties)94 function showBottomEdgePage(source, properties)
92 {95 {
@@ -142,13 +145,123 @@
142 z: 1145 z: 1
143 }146 }
144147
145 Timer {148 UbuntuShape {
146 id: hideIndicator149 id: tip
147150 objectName: "bottomEdgeTip"
148 interval: 3000151
149 running: true152 property bool hiden: (activeFocus === false) ||
150 repeat: false153 ((bottomEdge.y - units.gu(1)) < tip.y)
151 onTriggered: tip.hiden = true154
155 enabled: mouseArea.enabled
156 visible: page.bottomEdgeEnabled
157 anchors {
158 bottom: parent.bottom
159 horizontalCenter: bottomEdge.horizontalCenter
160 bottomMargin: hiden ? - height + units.gu(1) : -units.gu(1)
161 Behavior on bottomMargin {
162 SequentialAnimation {
163 // wait some msecs in case of the focus change again, to avoid flickering
164 PauseAnimation {
165 duration: 300
166 }
167 UbuntuNumberAnimation {
168 duration: UbuntuAnimation.SnapDuration
169 }
170 }
171 }
172 }
173
174 z: 1
175 width: tipLabel.paintedWidth + units.gu(6)
176 height: bottomEdge.tipHeight + units.gu(1)
177 color: Theme.palette.normal.overlay
178 Label {
179 id: tipLabel
180
181 anchors {
182 top: parent.top
183 left: parent.left
184 right: parent.right
185 }
186 height: bottomEdge.tipHeight
187 verticalAlignment: Text.AlignVCenter
188 horizontalAlignment: Text.AlignHCenter
189 opacity: tip.hiden ? 0.0 : 1.0
190 Behavior on opacity {
191 UbuntuNumberAnimation {
192 duration: UbuntuAnimation.SnapDuration
193 }
194 }
195 }
196 }
197
198 Rectangle {
199 id: shadow
200
201 anchors {
202 left: parent.left
203 right: parent.right
204 bottom: parent.bottom
205 }
206 height: units.gu(1)
207 z: 1
208 opacity: 0.0
209 gradient: Gradient {
210 GradientStop { position: 0.0; color: "transparent" }
211 GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
212 }
213 }
214
215 MouseArea {
216 id: mouseArea
217
218 property real previousY: -1
219 property string dragDirection: "None"
220
221 preventStealing: true
222 drag {
223 axis: Drag.YAxis
224 target: bottomEdge
225 minimumY: bottomEdge.pageStartY
226 maximumY: page.height
227 }
228 enabled: edgeLoader.status == Loader.Ready
229 visible: page.bottomEdgeEnabled
230
231 anchors {
232 left: parent.left
233 right: parent.right
234 bottom: parent.bottom
235 }
236 height: bottomEdge.tipHeight
237 z: 1
238
239 onReleased: {
240 page.bottomEdgeReleased()
241 if ((dragDirection === "BottomToTop") &&
242 bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
243 bottomEdge.state = "expanded"
244 } else {
245 bottomEdge.state = "collapsed"
246 }
247 previousY = -1
248 dragDirection = "None"
249 }
250
251 onPressed: {
252 previousY = mouse.y
253 tip.forceActiveFocus()
254 }
255
256 onMouseYChanged: {
257 var yOffset = previousY - mouseY
258 // skip if was a small move
259 if (Math.abs(yOffset) <= units.gu(2)) {
260 return
261 }
262 previousY = mouseY
263 dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
264 }
152 }265 }
153266
154 FakeHeader {267 FakeHeader {
@@ -177,7 +290,7 @@
177290
178 z: 1291 z: 1
179 color: Theme.palette.normal.background292 color: Theme.palette.normal.background
180 parent: page293 clip: true
181 anchors {294 anchors {
182 left: parent.left295 left: parent.left
183 right: parent.right296 right: parent.right
@@ -185,99 +298,7 @@
185 height: page.height298 height: page.height
186 y: height299 y: height
187300
188 UbuntuShape {301 visible: !page.isCollapsed
189 id: tip
190 objectName: "bottomEdgeTip"
191
192 property bool hiden: false
193
194 readonly property double visiblePosition: (page.height - bottomEdge.y) < units.gu(1) ? -bottomEdge.tipHeight + (page.height - bottomEdge.y) : 0
195 readonly property double invisiblePosition: (page.height - bottomEdge.y) < units.gu(1) ? -units.gu(1) : 0
196
197 z: -1
198 anchors.horizontalCenter: parent.horizontalCenter
199 y: hiden ? invisiblePosition : visiblePosition
200
201 width: tipLabel.paintedWidth + units.gu(6)
202 height: bottomEdge.tipHeight + units.gu(1)
203 color: Theme.palette.normal.overlay
204 Label {
205 id: tipLabel
206
207 anchors {
208 top: parent.top
209 left: parent.left
210 right: parent.right
211 }
212 height: bottomEdge.tipHeight
213 verticalAlignment: Text.AlignVCenter
214 horizontalAlignment: Text.AlignHCenter
215 opacity: tip.hiden ? 0.0 : 1.0
216 Behavior on opacity {
217 UbuntuNumberAnimation {
218 duration: UbuntuAnimation.SnapDuration
219 }
220 }
221 }
222 Behavior on y {
223 UbuntuNumberAnimation {
224 duration: UbuntuAnimation.SnapDuration
225 }
226 }
227 }
228
229 Rectangle {
230 id: shadow
231
232 anchors {
233 left: parent.left
234 right: parent.right
235 }
236 height: units.gu(1)
237 y: -height
238 z: -2
239 opacity: 0.0
240 gradient: Gradient {
241 GradientStop { position: 0.0; color: "transparent" }
242 GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
243 }
244 }
245
246 MouseArea {
247 id: mouseArea
248
249 preventStealing: true
250 drag {
251 axis: Drag.YAxis
252 target: bottomEdge
253 minimumY: bottomEdge.pageStartY
254 maximumY: page.height
255 threshold: 100
256 }
257
258 anchors {
259 left: parent.left
260 right: parent.right
261 }
262 height: bottomEdge.tipHeight
263 y: -height
264
265 onReleased: {
266 page.bottomEdgeReleased()
267 if (bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
268 bottomEdge.state = "expanded"
269 } else {
270 bottomEdge.state = "collapsed"
271 bottomEdge.y = bottomEdge.height
272 }
273 }
274
275 onClicked: {
276 tip.hiden = false
277 hideIndicator.restart()
278 }
279 }
280
281 state: "collapsed"302 state: "collapsed"
282 states: [303 states: [
283 State {304 State {
@@ -290,14 +311,6 @@
290 target: fakeHeader311 target: fakeHeader
291 y: -fakeHeader.height312 y: -fakeHeader.height
292 }313 }
293 PropertyChanges {
294 target: tip
295 opacity: 1.0
296 }
297 PropertyChanges {
298 target: hideIndicator
299 running: true
300 }
301 },314 },
302 State {315 State {
303 name: "expanded"316 name: "expanded"
@@ -309,10 +322,6 @@
309 target: fakeHeader322 target: fakeHeader
310 y: 0323 y: 0
311 }324 }
312 PropertyChanges {
313 target: hideIndicator
314 running: false
315 }
316 },325 },
317 State {326 State {
318 name: "floating"327 name: "floating"
@@ -321,14 +330,6 @@
321 target: shadow330 target: shadow
322 opacity: 1.0331 opacity: 1.0
323 }332 }
324 PropertyChanges {
325 target: hideIndicator
326 running: false
327 }
328 PropertyChanges {
329 target: tip
330 hiden: false
331 }
332 }333 }
333 ]334 ]
334335
@@ -336,18 +337,35 @@
336 Transition {337 Transition {
337 to: "expanded"338 to: "expanded"
338 SequentialAnimation {339 SequentialAnimation {
340 alwaysRunToEnd: true
339 ParallelAnimation {341 ParallelAnimation {
340 UbuntuNumberAnimation {342 SmoothedAnimation {
341 target: bottomEdge343 target: bottomEdge
342 property: "y"344 property: "y"
343 duration: UbuntuAnimation.SlowDuration345 duration: UbuntuAnimation.FastDuration
346 easing.type: Easing.Linear
344 }347 }
345 UbuntuNumberAnimation {348 SmoothedAnimation {
346 target: fakeHeader349 target: fakeHeader
347 property: "y"350 property: "y"
348 duration: UbuntuAnimation.SlowDuration351 duration: UbuntuAnimation.FastDuration
352 easing.type: Easing.Linear
349 }353 }
350 }354 }
355 SmoothedAnimation {
356 target: edgeLoader
357 property: "anchors.topMargin"
358 to: - units.gu(4)
359 duration: UbuntuAnimation.FastDuration
360 easing.type: Easing.Linear
361 }
362 SmoothedAnimation {
363 target: edgeLoader
364 property: "anchors.topMargin"
365 to: 0
366 duration: UbuntuAnimation.FastDuration
367 easing: UbuntuAnimation.StandardEasing
368 }
351 ScriptAction {369 ScriptAction {
352 script: page._pushPage()370 script: page._pushPage()
353 }371 }
@@ -357,6 +375,8 @@
357 from: "expanded"375 from: "expanded"
358 to: "collapsed"376 to: "collapsed"
359 SequentialAnimation {377 SequentialAnimation {
378 alwaysRunToEnd: true
379
360 ScriptAction {380 ScriptAction {
361 script: {381 script: {
362 Qt.inputMethod.hide()382 Qt.inputMethod.hide()
@@ -366,12 +386,12 @@
366 }386 }
367 }387 }
368 ParallelAnimation {388 ParallelAnimation {
369 UbuntuNumberAnimation {389 SmoothedAnimation {
370 target: bottomEdge390 target: bottomEdge
371 property: "y"391 property: "y"
372 duration: UbuntuAnimation.SlowDuration392 duration: UbuntuAnimation.SlowDuration
373 }393 }
374 UbuntuNumberAnimation {394 SmoothedAnimation {
375 target: fakeHeader395 target: fakeHeader
376 property: "y"396 property: "y"
377 duration: UbuntuAnimation.SlowDuration397 duration: UbuntuAnimation.SlowDuration
@@ -382,14 +402,14 @@
382 // destroy current bottom page402 // destroy current bottom page
383 if (page.reloadBottomEdgePage) {403 if (page.reloadBottomEdgePage) {
384 edgeLoader.active = false404 edgeLoader.active = false
405 } else {
406 tip.forceActiveFocus()
385 }407 }
386408
387 // notify409 // notify
388 page.bottomEdgeDismissed()410 page.bottomEdgeDismissed()
389411
390 edgeLoader.active = true412 edgeLoader.active = true
391 tip.hiden = false
392 hideIndicator.restart()
393 }413 }
394 }414 }
395 }415 }
@@ -404,30 +424,23 @@
404 }424 }
405 ]425 ]
406426
407 Item {427 Loader {
428 id: edgeLoader
429
430 asynchronous: true
408 anchors.fill: parent431 anchors.fill: parent
409 clip: true432 //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
410433 Binding {
411 Loader {434 target: edgeLoader.status === Loader.Ready ? edgeLoader : null
412 id: edgeLoader435 property: "anchors.topMargin"
413436 value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
414 z: 1437 when: !page.isReady
415 active: true438 }
416 asynchronous: true439
417 anchors.fill: parent440 onLoaded: {
418441 tip.forceActiveFocus()
419 //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging442 if (page.isReady && edgeLoader.item.active !== true) {
420 Binding {443 page._pushPage()
421 target: edgeLoader.status === Loader.Ready ? edgeLoader : null
422 property: "anchors.topMargin"
423 value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
424 when: !page.isReady
425 }
426
427 onLoaded: {
428 if (page.isReady && edgeLoader.item.active !== true) {
429 page._pushPage()
430 }
431 }444 }
432 }445 }
433 }446 }
434447
=== modified file 'app/worldclock/UserWorldCityList.qml'
--- app/worldclock/UserWorldCityList.qml 2014-08-24 12:47:50 +0000
+++ app/worldclock/UserWorldCityList.qml 2014-10-05 15:35:22 +0000
@@ -21,8 +21,6 @@
21import U1db 1.0 as U1db21import U1db 1.0 as U1db
22import Ubuntu.Components 1.122import Ubuntu.Components 1.1
2323
24import "../components/Utils.js" as Utils
25
26Column {24Column {
27 id: worldCityColumn25 id: worldCityColumn
2826
2927
=== modified file 'tests/autopilot/ubuntu_clock_app/emulators.py'
--- tests/autopilot/ubuntu_clock_app/emulators.py 2014-09-12 19:44:18 +0000
+++ tests/autopilot/ubuntu_clock_app/emulators.py 2014-10-05 15:35:22 +0000
@@ -91,6 +91,8 @@
91 self.bottomEdgePageLoaded.wait_for(True)91 self.bottomEdgePageLoaded.wait_for(True)
92 try:92 try:
93 action_item = self.wait_select_single(objectName='bottomEdgeTip')93 action_item = self.wait_select_single(objectName='bottomEdgeTip')
94 action_item.hiden.wait_for(False)
95 action_item.enabled.wait_for(True)
94 start_x = (action_item.globalRect.x +96 start_x = (action_item.globalRect.x +
95 (action_item.globalRect.width * 0.5))97 (action_item.globalRect.width * 0.5))
96 start_y = (action_item.globalRect.y +98 start_y = (action_item.globalRect.y +
9799
=== modified file 'tests/unit/tst_alarm.qml'
--- tests/unit/tst_alarm.qml 2014-09-25 22:10:27 +0000
+++ tests/unit/tst_alarm.qml 2014-10-05 15:35:22 +0000
@@ -18,6 +18,7 @@
1818
19import QtQuick 2.319import QtQuick 2.3
20import QtTest 1.020import QtTest 1.0
21import DateTime 1.0
21import Ubuntu.Test 1.022import Ubuntu.Test 1.0
22import Ubuntu.Components 1.123import Ubuntu.Components 1.1
23import "../../app/alarm"24import "../../app/alarm"
@@ -29,10 +30,26 @@
29 height: units.gu(70)30 height: units.gu(70)
30 useDeprecatedToolbar: false31 useDeprecatedToolbar: false
3132
33 property var clockTime: new Date
34 (
35 localTimeSource.localDateString.split(":")[0],
36 localTimeSource.localDateString.split(":")[1]-1,
37 localTimeSource.localDateString.split(":")[2],
38 localTimeSource.localTimeString.split(":")[0],
39 localTimeSource.localTimeString.split(":")[1],
40 localTimeSource.localTimeString.split(":")[2],
41 localTimeSource.localTimeString.split(":")[3]
42 )
43
32 AlarmModel {44 AlarmModel {
33 id: alarmModel45 id: alarmModel
34 }46 }
3547
48 DateTime {
49 id: localTimeSource
50 updateInterval: 1000
51 }
52
36 PageStack {53 PageStack {
37 id: pageStack54 id: pageStack
38 Component.onCompleted: push(alarmPage)55 Component.onCompleted: push(alarmPage)

Subscribers

People subscribed via source and target branches