Merge lp:~ubuntu-clock-dev/ubuntu-clock-app/stopwatch-feature-staging into lp:ubuntu-clock-app

Proposed by Nekhelesh Ramananthan
Status: Merged
Approved by: Bartosz Kosiorek
Approved revision: 380
Merged at revision: 340
Proposed branch: lp:~ubuntu-clock-dev/ubuntu-clock-app/stopwatch-feature-staging
Merge into: lp:ubuntu-clock-app
Diff against target: 2139 lines (+1391/-309)
32 files modified
AUTHORS (+1/-0)
app/CMakeLists.txt (+2/-0)
app/MainPage.qml (+121/-0)
app/clock/ClockPage.qml (+126/-176)
app/components/ActionIcon.qml (+45/-0)
app/components/CMakeLists.txt (+2/-0)
app/components/HeaderNavigation.qml (+86/-0)
app/graphics/CMakeLists.txt (+2/-0)
app/graphics/Stopwatch_Placeholder.svg (+19/-0)
app/graphics/WorldClock_Placeholder.svg (+22/-0)
app/stopwatch/CMakeLists.txt (+11/-0)
app/stopwatch/LapListView.qml (+140/-0)
app/stopwatch/StopwatchFace.qml (+61/-0)
app/stopwatch/StopwatchPage.qml (+169/-0)
app/stopwatch/StopwatchUtils.qml (+73/-0)
app/ubuntu-clock-app.qml (+19/-20)
app/worldclock/AddWorldCityButton.qml (+8/-4)
app/worldclock/UserWorldCityList.qml (+94/-93)
backend/CMakeLists.txt (+25/-0)
backend/modules/Stopwatch/LapHistory/backend.cpp (+34/-0)
backend/modules/Stopwatch/LapHistory/backend.h (+35/-0)
backend/modules/Stopwatch/LapHistory/history.cpp (+97/-0)
backend/modules/Stopwatch/LapHistory/history.h (+64/-0)
backend/modules/Stopwatch/LapHistory/qmldir (+2/-0)
debian/changelog (+2/-0)
debian/control (+2/-0)
po/com.ubuntu.clock.pot (+38/-8)
tests/unit/CMakeLists.txt (+2/-0)
tests/unit/MockClockApp.qml (+6/-5)
tests/unit/tst_stopwatchUtils.qml (+79/-0)
tests/unit/tst_worldClock.qml (+1/-1)
ubuntu-clock-app.json (+3/-2)
To merge this branch: bzr merge lp:~ubuntu-clock-dev/ubuntu-clock-app/stopwatch-feature-staging
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Bartosz Kosiorek Approve
Victor Thompson Needs Fixing
Review via email: mp+266718@code.launchpad.net

Commit message

Implement the new stopwatch feature

Description of the change

This is a staging MP for the stopwatch feature. All intermediate stopwatch code implementation should be merged into this branch while keep trunk clean and stable.

Things Implemented:
-------------------
- New navigation model
- Stopwatch UI
- Stopwatch backend JS functions
- Stopwatch Laps model & ui
- Header row (icon based navigation model)
- Credited Michael Zanetti for his code in the Authors file
- Minor performance optimization done (unload stopwatch laps when not running, disable bottom-edge in stopwatch tab, stop checking time to next alarm when mainpage is not visible)
- Ran timekeeping test and it performed quite well
- Unit tests
- Rebuilt .pot file
- Manual testing
- UX Feedback/Approval received from James Mullholland.
- Final finishing touches
- Disabled page scrolling after informing James. Will be fixed in another MP later.
- Merged bartosz's MP lp:~ubuntu-clock-dev/ubuntu-clock-app/stopwatch-feature-extended

Note:

For the stopwatch backend, let's use the reference implementation of https://uappexplorer.com/app/stopwatch.mzanetti. It seems to be working quite good with simple qml+js code.

Check out https://bazaar.launchpad.net/~mzanetti/+junk/stopwatch/view/head:/app/StopWatch.qml for the code.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
335. By Nekhelesh Ramananthan

Improved header navigation by making it part of the page flickable

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Bartosz Kosiorek (gang65) wrote :

Awensome work Nekhelesh.

Here my 2 cents:
1. Clicking/touching stopwatch icon should swipe to the corresponding Page (Stopwatch, World Clock)
2. In full sun it is hard to read when stopwatch is enabled, and when not. Some improvement proposal:
   - Change "Start" button color to green and "Stop" button color to red.
   - Enable "Seconds hand". I will visualise the stopwatch progress. It will be also very similar with World Clock. When you press "Lap" button, it will be restarted.
3. During pressing "Lap" it is hard to notice what was happen. Some numbers are changing. Maybe some small "lap scroll down" animation will improve that UX. What do you think?
4. It will be good to add some visual details which will be unique for Stop Watch, so user will know for first look what page it is displayed.

review: Needs Information
336. By Nekhelesh Ramananthan

Changed start/stop button color to green and red for better visual distinction

337. By Nekhelesh Ramananthan

Made the header navigation buttons clickable

338. By Nekhelesh Ramananthan

Increased speed of screen switch transition

Revision history for this message
Nekhelesh Ramananthan (nik90) wrote :

> 1. Clicking/touching stopwatch icon should swipe to the corresponding Page
> (Stopwatch, World Clock)

Fixed

> 2. In full sun it is hard to read when stopwatch is enabled, and when not.
> Some improvement proposal:
> - Change "Start" button color to green and "Stop" button color to red.

Fixed

> - Enable "Seconds hand". I will visualise the stopwatch progress. It will
> be also very similar with World Clock. When you press "Lap" button, it will be
> restarted.

Needs visuals for this. Let's discuss with designers.

> 3. During pressing "Lap" it is hard to notice what was happen. Some numbers
> are changing. Maybe some small "lap scroll down" animation will improve that
> UX. What do you think?

Fixed

> 4. It will be good to add some visual details which will be unique for Stop
> Watch, so user will know for first look what page it is displayed.

I need some visuals for this. I did look at http://design.canonical.com/wp-content/uploads/keyscreens_clock.jpg, but need to brainstorm on how to integrate that with the current design.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
339. By Nekhelesh Ramananthan

Disable flickable scrolling when content height is less than phone height

340. By Nekhelesh Ramananthan

Disabled screen switching by swiping as it conflicts with listitem swipe-to-delete gesture

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Victor Thompson (vthompson) wrote :

I get the following in the logs before the app crashes:

file:///opt/click.ubuntu.com/com.ubuntu.clock/3.5./share/qml/components/HeaderNavigation.qml:32 ActionIcon is not a type

Is this component perhaps only available on wily/devel-proposed?

review: Needs Fixing
Revision history for this message
Victor Thompson (vthompson) wrote :

Disregard my last comment. It seems I needed to refresh/reload the project so the file would be found by QtCreator.

Revision history for this message
Bartosz Kosiorek (gang65) wrote :

Some more remarks:
1. With current implementation page swiping is not working any more.
2. In my opinion the time list is not easy to read, at first look:
  - It is hard to say which time is lap and which total time. In https://uappexplorer.com/app/stopwatch.mzanetti there are additionals description for every row.
  - It is hard to compare time results. In https://uappexplorer.com/app/stopwatch.mzanetti the hours is not displayed and miliseconds are smaller
  - Currently time list it looks like: http://i.imgur.com/qxh932g.png

review: Needs Fixing
341. By Victor Thompson

Use the word resume if the timer has started

Revision history for this message
Victor Thompson (vthompson) wrote :

This would need UX approval, but I think tapping the clock face should start/stop the timer as well. Since the "clock" functionality of the app allows the user to "toggle" an action using the clock face, I think this functionality should probably do so as well--in addition to the button.

342. By Victor Thompson

Don't show clear button if nothing to clear

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Victor Thompson (vthompson) wrote :

I'm not sure if everyone will be on board with my latest small change. I made it so if the timer hasn't counted any time, that the clear/lap button isn't shown and only the Start button is shown. This is how my Android stopwatch (Google Clock) behaves. Please feel free to revert r342 if anyone disagrees with this.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Bartosz Kosiorek (gang65) wrote :

Some additional inline comments

review: Needs Fixing
Revision history for this message
Nekhelesh Ramananthan (nik90) wrote :

@Bartosz I addressed the inline comments in the latest commit. Fixed many of them and explained the reasoning for the rest.

343. By Nekhelesh Ramananthan

Merged lp:ubuntu-clock-app trunk changes

344. By Nekhelesh Ramananthan

Fixed some code styling and improve stopwatch utils functions

345. By Nekhelesh Ramananthan

Updated debian changelog

Revision history for this message
Nekhelesh Ramananthan (nik90) wrote :

> Some more remarks:
> 1. With current implementation page swiping is not working any more.

Yes, that's intentional since the swipe-to-delete world city gesture is conflicting with the page swiping gesture. I talked to Unity developers like Michael Zanetti and agree that disabling that is the best way to go. I will bring this up with the designers when we meet.

> 2. In my opinion the time list is not easy to read, at first look:
> - It is hard to say which time is lap and which total time. In
> https://uappexplorer.com/app/stopwatch.mzanetti there are additionals
> description for every row.
> - It is hard to compare time results. In
> https://uappexplorer.com/app/stopwatch.mzanetti the hours is not displayed and
> miliseconds are smaller
> - Currently time list it looks like: http://i.imgur.com/qxh932g.png

I totally agree to both your points. If you look at the design document given to us, it didn't have a lap design. So I just temporarily just implemented something temporarily. I feel that the mzanetti's stopwatch app is a bit crowded. So I don't think showing the string "totalTime" and "laptime" for every list item would look nice. Perhaps as a header maybe? I will see what I can come up with or ask the designers.

Revision history for this message
Nekhelesh Ramananthan (nik90) wrote :

> I'm not sure if everyone will be on board with my latest small change. I made
> it so if the timer hasn't counted any time, that the clear/lap button isn't
> shown and only the Start button is shown. This is how my Android stopwatch
> (Google Clock) behaves. Please feel free to revert r342 if anyone disagrees
> with this.

Both the changes you merged to the branch are good. I will make a small improvement to it by adding a small property animation when the lap button is shown/hidden to ease the transition :).

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
346. By Nekhelesh Ramananthan

Added a nice sexy animation when hiding/showing the lap button. Enjoy!

347. By Nekhelesh Ramananthan

Added a lap header to help distinguish between laptime and totaltime

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Bartosz Kosiorek (gang65) wrote :

Some more inline remarks.

review: Needs Fixing
Revision history for this message
Nekhelesh Ramananthan (nik90) wrote :

Addressed most of the inline comments in latest commit.

348. By Nekhelesh Ramananthan

Changed lap# to just lap

349. By Nekhelesh Ramananthan

Ensured lap number respects user locale

350. By Nekhelesh Ramananthan

Replaced GLOB to Set in stopwatch CMake file

351. By Nekhelesh Ramananthan

Merged lp:ubuntu-clock-app

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
352. By Nekhelesh Ramananthan

Added unit tests to stopwatch utils functions

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
353. By Nekhelesh Ramananthan

Fixed stopwatch buttons behaving strangely when returning from the settings page

354. By Nekhelesh Ramananthan

Moved header row to main page instead of duplicating it in every page. Also made listview horizontally scrollable

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
355. By Nekhelesh Ramananthan

merged trunk lp:ubuntu-clock-app

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
356. By Nekhelesh Ramananthan

Merged trunk lp:ubuntu-clock-app

357. By Nekhelesh Ramananthan

Disabled screen dimming when stopwatch is running

358. By Nekhelesh Ramananthan

Merged lp:ubuntu-clock-app

359. By Nekhelesh Ramananthan

Tweaked CMakelist file to include HeaderNavigation and ActionIcon

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
360. By Nekhelesh Ramananthan

Updated clock app dependency to include qml-module-qtsysteminfo without which jenkins fails

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Bartosz Kosiorek (gang65) wrote :

Here is what I'm missing with current StopWatch implementation:
1. Saving laps in database after pressing Lap or stop Button. After close and run Clock application, the results should be still there
2. When you start stopwatch the starttime should be stored in database. After closing Clock app, and reopening it, the time should be still counting (we could just calculate difference between starttime and current time).

These features could be implemented later, but this is good input for UX approval

review: Needs Information
361. By Bartosz Kosiorek

Keep running stopwatch in the background,
even when the phone/clock app is turned off (LP: #1484942)

362. By Bartosz Kosiorek

Remove uneccesary comment

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
363. By Nekhelesh Ramananthan

Reverted r361 and r362

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
364. By Nekhelesh Ramananthan

Removed Flickables and split vertical pane into 2 as per design. Also removed Flickup and FlickDown signals as they are no longer needed

365. By Nekhelesh Ramananthan

Added more official icon placeholders

366. By Nekhelesh Ramananthan

merged lp:ubuntu-clock-app trunk

367. By Nekhelesh Ramananthan

Minor anchor change to remove unnecessary design change

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
368. By Nekhelesh Ramananthan

first attempt at fixing unit test

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
369. By Nekhelesh Ramananthan

Updated pot file

370. By Nekhelesh Ramananthan

Removed remaining FlickUp FlickDown signal

371. By Nekhelesh Ramananthan

More code cleanup

372. By Nekhelesh Ramananthan

Added comment

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
373. By Nekhelesh Ramananthan

Reduced font size of milliseconds and hid the hours in the laptime when possible. Added units to cover this function

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
374. By Nekhelesh Ramananthan

Merged lp:ubuntu-clock-app

375. By Nekhelesh Ramananthan

Disabled page swipe gesture after getting approval from james

376. By Nekhelesh Ramananthan

Increased height of add world city button container

377. By Nekhelesh Ramananthan

Changed color of settings icon to match rest of the header icons

378. By Nekhelesh Ramananthan

Fixed minor anchoring issue

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
379. By Nekhelesh Ramananthan

Merged bartosz stopwatch-feature-extended branch

380. By Nekhelesh Ramananthan

Updated pot file one last time

Revision history for this message
Bartosz Kosiorek (gang65) wrote :

I tested it on Desktop and device and I didn't notice any issues.

review: Approve
Revision history for this message
Bartosz Kosiorek (gang65) wrote :

* Does the MP add/remove user visible strings? If Yes, has the pot file been
    updated?

Updated

* Does the MP change the UI? If Yes, has it been approved by design?

UX change was approved.

* Did you perform an exploratory manual test run of your code change and any
    related functionality?

Extensive testing done on desktop and phone

* If the MP fixes a bug or implements a feature, are there accompanying unit
    and autopilot tests?

Not required

* Is the clock app trunk buildable and runnable using Qtcreator?

Yes
* Was the debian changelog updated?

Yes

* Was the copyright years updated if necessary?

Yes

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'AUTHORS'
2--- AUTHORS 2015-07-06 17:17:59 +0000
3+++ AUTHORS 2015-08-20 20:43:05 +0000
4@@ -25,6 +25,7 @@
5 Marco Biscaro <marcobiscaro2112@gmail.com>
6 Mario Guerriero <mefrio.g@gmail.com>
7 Michael Hall <mhall119@ubuntu.com>
8+Michael Zanetti <michael.zanetti@canonical.com>
9 Michal Predotka <mpredotka@gmail.com>
10 Michał Sawicz <michal.sawicz@canonical.com>
11 Nekhelesh Ramananthan <krnekhelesh@hotmail.com>
12
13=== modified file 'app/CMakeLists.txt'
14--- app/CMakeLists.txt 2014-09-26 16:58:03 +0000
15+++ app/CMakeLists.txt 2015-08-20 20:43:05 +0000
16@@ -10,9 +10,11 @@
17 endif(CLICK_MODE)
18
19 install(FILES ${MAIN_QML} DESTINATION ${UBUNTU-CLOCK_APP_DIR})
20+install(FILES "MainPage.qml" DESTINATION ${UBUNTU-CLOCK_APP_DIR})
21
22 add_subdirectory(clock)
23 add_subdirectory(alarm)
24+add_subdirectory(stopwatch)
25 add_subdirectory(graphics)
26 add_subdirectory(components)
27 add_subdirectory(worldclock)
28
29=== added file 'app/MainPage.qml'
30--- app/MainPage.qml 1970-01-01 00:00:00 +0000
31+++ app/MainPage.qml 2015-08-20 20:43:05 +0000
32@@ -0,0 +1,121 @@
33+/*
34+ * Copyright (C) 2015 Canonical Ltd
35+ *
36+ * This file is part of Ubuntu Clock App
37+ *
38+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
39+ * it under the terms of the GNU General Public License version 3 as
40+ * published by the Free Software Foundation.
41+ *
42+ * Ubuntu Clock App is distributed in the hope that it will be useful,
43+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
44+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45+ * GNU General Public License for more details.
46+ *
47+ * You should have received a copy of the GNU General Public License
48+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
49+ */
50+
51+import QtQuick 2.4
52+import Ubuntu.Components 1.2
53+import QtSystemInfo 5.0
54+import Qt.labs.settings 1.0
55+import "upstreamcomponents"
56+import "alarm"
57+import "clock"
58+import "stopwatch"
59+import "components"
60+
61+PageWithBottomEdge {
62+ id: _mainPage
63+ objectName: "mainPage"
64+
65+ // Property to keep track of the clock time
66+ property var clockTime: new Date()
67+
68+ // Property to keep track of an app cold start status
69+ property alias isColdStart: clockPage.isColdStart
70+
71+ // Property to check if the clock page is currently visible
72+ property bool isClockPage: listview.currentIndex === 0
73+
74+ // Clock App Alarm Model Reference Variable
75+ property var alarmModel
76+
77+ flickable: null
78+ bottomEdgeTitle: _mainPage.visible ? alarmUtils.set_bottom_edge_title(alarmModel, clockTime)
79+ : i18n.tr("No active alarms")
80+
81+ Component.onCompleted: {
82+ console.log("[LOG]: Main Page loaded")
83+ _mainPage.setBottomEdgePage(Qt.resolvedUrl("alarm/AlarmPage.qml"), {})
84+ }
85+
86+ AlarmUtils {
87+ id: alarmUtils
88+ }
89+
90+ ScreenSaver {
91+ // Disable screen dimming/off when stopwatch is running
92+ screenSaverEnabled: !stopwatchPage.running
93+ }
94+
95+ Settings {
96+ id: stopwatchState
97+ category: "Stopwatch"
98+ property alias startTime: stopwatchPage.startTime
99+ property alias running: stopwatchPage.running
100+ property alias oldDiff: stopwatchPage.oldDiff
101+ }
102+
103+ VisualItemModel {
104+ id: navigationModel
105+ ClockPage {
106+ id: clockPage
107+ clockTime: _mainPage.clockTime
108+ width: clockApp.width
109+ height: listview.height
110+ }
111+
112+ StopwatchPage {
113+ id: stopwatchPage
114+ width: clockApp.width
115+ height: listview.height
116+ }
117+ }
118+
119+ HeaderNavigation {
120+ id: headerRow
121+
122+ anchors {
123+ top: parent.top
124+ left: parent.left
125+ right: parent.right
126+ topMargin: 0
127+ }
128+ }
129+
130+ ListView {
131+ id: listview
132+
133+ // Show the stopwatch page on app startup if it is running
134+ Component.onCompleted: {
135+ if (stopwatchState.running)
136+ positionViewAtIndex(1, ListView.SnapPosition)
137+ }
138+
139+ anchors {
140+ top: headerRow.bottom
141+ left: parent.left
142+ right: parent.right
143+ bottom: parent.bottom
144+ }
145+
146+ model: navigationModel
147+ orientation: ListView.Horizontal
148+ snapMode: ListView.SnapOneItem
149+ interactive: false
150+ highlightMoveDuration: UbuntuAnimation.BriskDuration
151+ highlightRangeMode: ListView.StrictlyEnforceRange
152+ }
153+}
154
155=== modified file 'app/clock/ClockPage.qml'
156--- app/clock/ClockPage.qml 2015-08-07 11:45:17 +0000
157+++ app/clock/ClockPage.qml 2015-08-20 20:43:05 +0000
158@@ -21,12 +21,10 @@
159 import QtPositioning 5.2
160 import Ubuntu.Components 1.2
161 import GeoLocation 1.0
162-import "../alarm"
163 import "../components"
164-import "../upstreamcomponents"
165 import "../worldclock"
166
167-PageWithBottomEdge {
168+Item {
169 id: _clockPage
170 objectName: "clockPage"
171
172@@ -39,18 +37,9 @@
173 // Property to keep track of app cold start status
174 property alias isColdStart: clock.isColdStart
175
176- property var alarmModel
177-
178- flickable: null
179- bottomEdgeTitle: alarmUtils.set_bottom_edge_title(alarmModel, clockTime)
180-
181 Component.onCompleted: {
182 console.log("[LOG]: Clock Page loaded")
183- _clockPage.setBottomEdgePage(Qt.resolvedUrl("../alarm/AlarmPage.qml"), {})
184- }
185-
186- AlarmUtils {
187- id: alarmUtils
188+ otherElementsStartUpAnimation.start()
189 }
190
191 PositionSource {
192@@ -167,178 +156,139 @@
193 }
194 }
195
196- Flickable {
197- id: _flickable
198-
199- Component.onCompleted: otherElementsStartUpAnimation.start()
200-
201- onFlickStarted: {
202- forceActiveFocus()
203- }
204-
205- anchors.fill: parent
206- contentWidth: parent.width
207- contentHeight: clock.height + date.height + locationRow.height
208- + worldCityColumn.height + addWorldCityButton.height
209- + units.gu(16)
210-
211- AbstractButton {
212- id: settingsIcon
213- objectName: "settingsIcon"
214-
215- onClicked: {
216- mainStack.push(Qt.resolvedUrl("../alarm/AlarmSettingsPage.qml"))
217- }
218-
219- width: units.gu(5)
220- height: width
221- opacity: 0
222-
223- anchors {
224- top: parent.top
225- topMargin: units.gu(6)
226- right: parent.right
227- rightMargin: units.gu(2)
228- }
229-
230- Rectangle {
231- visible: settingsIcon.pressed
232- anchors.fill: parent
233- color: Theme.palette.selected.background
234- }
235-
236- Icon {
237- width: units.gu(3)
238- height: width
239- anchors.centerIn: parent
240- name: "settings"
241- color: "Grey"
242- }
243- }
244-
245- MainClock {
246- id: clock
247- objectName: "clock"
248-
249- Component.onCompleted: {
250- geoposition.lastUpdate = analogTime
251- }
252-
253- analogTime: clockTime
254-
255- anchors {
256- verticalCenter: parent.top
257- verticalCenterOffset: units.gu(20)
258- horizontalCenter: parent.horizontalCenter
259- }
260+ MainClock {
261+ id: clock
262+ objectName: "clock"
263+
264+ Component.onCompleted: {
265+ geoposition.lastUpdate = analogTime
266+ }
267+
268+ analogTime: clockTime
269+
270+ anchors {
271+ verticalCenter: parent.top
272+ verticalCenterOffset: units.gu(18)
273+ horizontalCenter: parent.horizontalCenter
274+ }
275+ }
276+
277+ Label {
278+ id: date
279+
280+ anchors {
281+ top: parent.top
282+ topMargin: units.gu(41)
283+ horizontalCenter: parent.horizontalCenter
284+ }
285+
286+ text: clock.analogTime.toLocaleDateString()
287+
288+ opacity: 0
289+ color: locationRow.visible ? Theme.palette.normal.baseText : UbuntuColors.midAubergine
290+ fontSize: "medium"
291+ }
292+
293+ Row {
294+ id: locationRow
295+ objectName: "locationRow"
296+
297+ opacity: date.opacity
298+ spacing: units.gu(1)
299+ visible: location.text !== "Null" && location.text !== "Denied"
300+
301+ anchors {
302+ top: date.bottom
303+ topMargin: units.gu(1)
304+ horizontalCenter: parent.horizontalCenter
305+ }
306+
307+ Icon {
308+ id: locationIcon
309+ name: "location"
310+ height: units.gu(2.2)
311+ color: "Grey"
312 }
313
314 Label {
315- id: date
316-
317- anchors {
318- top: parent.top
319- topMargin: units.gu(36)
320- horizontalCenter: parent.horizontalCenter
321- }
322-
323- text: clock.analogTime.toLocaleDateString()
324- opacity: settingsIcon.opacity
325- color: locationRow.visible ? Theme.palette.normal.baseText : UbuntuColors.midAubergine
326+ id: location
327+ objectName: "location"
328+
329 fontSize: "medium"
330+ anchors.verticalCenter: locationIcon.verticalCenter
331+ color: UbuntuColors.midAubergine
332+
333+ text: {
334+ if (userLocationDocument.contents.location === "Null"
335+ || userLocationDocument.contents.location === "Denied"
336+ && geoposition.sourceError === PositionSource.NoError) {
337+ return i18n.tr("Retrieving location...")
338+ }
339+
340+ else {
341+ return userLocationDocument.contents.location
342+ }
343+ }
344 }
345-
346- Row {
347- id: locationRow
348- objectName: "locationRow"
349-
350- opacity: settingsIcon.opacity
351- spacing: units.gu(1)
352- visible: location.text !== "Null" && location.text !== "Denied"
353-
354- anchors {
355- top: date.bottom
356- topMargin: units.gu(1)
357- horizontalCenter: parent.horizontalCenter
358- }
359-
360- Icon {
361- id: locationIcon
362- name: "location"
363- height: units.gu(2.2)
364- color: "Grey"
365- }
366-
367- Label {
368- id: location
369- objectName: "location"
370-
371- fontSize: "medium"
372- anchors.verticalCenter: locationIcon.verticalCenter
373- color: UbuntuColors.midAubergine
374-
375- text: {
376- if (userLocationDocument.contents.location === "Null"
377- || userLocationDocument.contents.location === "Denied"
378- && geoposition.sourceError === PositionSource.NoError) {
379- return i18n.tr("Retrieving location...")
380- }
381-
382- else {
383- return userLocationDocument.contents.location
384- }
385- }
386- }
387+ }
388+
389+ MouseArea {
390+ id: worldCityListMouseArea
391+
392+ preventStealing: true
393+
394+ anchors {
395+ top: locationRow.bottom
396+ topMargin: units.gu(2)
397+ bottom: parent.bottom
398+ left: parent.left
399+ right: parent.right
400 }
401
402 UserWorldCityList {
403 id: worldCityColumn
404- objectName: "worldCityColumn"
405-
406- opacity: settingsIcon.opacity
407- anchors {
408- top: locationRow.bottom
409- topMargin: units.gu(4)
410- }
411- }
412-
413- AddWorldCityButton {
414- id: addWorldCityButton
415- objectName: "addWorldCityButton"
416-
417- opacity: settingsIcon.opacity
418- anchors {
419- top: worldCityColumn.bottom
420- topMargin: units.gu(1)
421- }
422- }
423-
424- ParallelAnimation {
425- id: otherElementsStartUpAnimation
426-
427- PropertyAnimation {
428- target: settingsIcon
429- property: "anchors.topMargin"
430- from: units.gu(6)
431- to: units.gu(2)
432- duration: 900
433- }
434-
435- PropertyAnimation {
436- target: settingsIcon
437- property: "opacity"
438- from: 0
439- to: 1
440- duration: 900
441- }
442-
443- PropertyAnimation {
444- target: date
445- property: "anchors.topMargin"
446- from: units.gu(36)
447- to: units.gu(40)
448- duration: 900
449- }
450+ opacity: date.opacity
451+
452+ footer: AddWorldCityButton {
453+ id: addWorldCityButton
454+ objectName: "addWorldCityButton"
455+ }
456+ }
457+ }
458+
459+ ParallelAnimation {
460+ id: otherElementsStartUpAnimation
461+
462+ PropertyAnimation {
463+ target: headerRow
464+ property: "anchors.topMargin"
465+ from: units.gu(4)
466+ to: 0
467+ duration: 900
468+ }
469+
470+ PropertyAnimation {
471+ target: headerRow
472+ property: "opacity"
473+ from: 0
474+ to: 1
475+ duration: 900
476+ }
477+
478+ PropertyAnimation {
479+ target: date
480+ property: "opacity"
481+ from: 0
482+ to: 1
483+ duration: 900
484+ }
485+
486+ PropertyAnimation {
487+ target: date
488+ property: "anchors.topMargin"
489+ from: units.gu(41)
490+ to: units.gu(37)
491+ duration: 900
492 }
493 }
494 }
495
496=== added file 'app/components/ActionIcon.qml'
497--- app/components/ActionIcon.qml 1970-01-01 00:00:00 +0000
498+++ app/components/ActionIcon.qml 2015-08-20 20:43:05 +0000
499@@ -0,0 +1,45 @@
500+/*
501+ * Copyright (C) 2015 Canonical Ltd
502+ *
503+ * This file is part of Ubuntu Clock App
504+ *
505+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
506+ * it under the terms of the GNU General Public License version 3 as
507+ * published by the Free Software Foundation.
508+ *
509+ * Ubuntu Clock App is distributed in the hope that it will be useful,
510+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
511+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
512+ * GNU General Public License for more details.
513+ *
514+ * You should have received a copy of the GNU General Public License
515+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
516+ */
517+
518+import QtQuick 2.4
519+import Ubuntu.Components 1.2
520+
521+AbstractButton {
522+ id: abstractButton
523+
524+ property alias iconName: _icon.name
525+ property alias iconSource: _icon.source
526+ property alias iconWidth: _icon.width
527+
528+ width: units.gu(5)
529+ height: width
530+
531+ Rectangle {
532+ visible: abstractButton.pressed
533+ anchors.fill: parent
534+ color: Theme.palette.selected.background
535+ }
536+
537+ Icon {
538+ id: _icon
539+ width: units.gu(3)
540+ height: width
541+ anchors.centerIn: parent
542+ color: "#5B5B5B"
543+ }
544+}
545
546=== modified file 'app/components/CMakeLists.txt'
547--- app/components/CMakeLists.txt 2015-08-11 15:05:34 +0000
548+++ app/components/CMakeLists.txt 2015-08-20 20:43:05 +0000
549@@ -1,4 +1,5 @@
550 set(COMPONENTS_QML_JS_FILES
551+ ActionIcon.qml
552 AnalogMode.qml
553 AnalogShadow.qml
554 Background.qml
555@@ -8,6 +9,7 @@
556 DigitalShadow.qml
557 EmptyState.qml
558 ExpandableListItem.qml
559+ HeaderNavigation.qml
560 Shadow.qml
561 SubtitledListItem.qml
562 )
563
564=== added file 'app/components/HeaderNavigation.qml'
565--- app/components/HeaderNavigation.qml 1970-01-01 00:00:00 +0000
566+++ app/components/HeaderNavigation.qml 2015-08-20 20:43:05 +0000
567@@ -0,0 +1,86 @@
568+/*
569+ * Copyright (C) 2015 Canonical Ltd
570+ *
571+ * This file is part of Ubuntu Clock App
572+ *
573+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
574+ * it under the terms of the GNU General Public License version 3 as
575+ * published by the Free Software Foundation.
576+ *
577+ * Ubuntu Clock App is distributed in the hope that it will be useful,
578+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
579+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
580+ * GNU General Public License for more details.
581+ *
582+ * You should have received a copy of the GNU General Public License
583+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
584+ */
585+
586+import QtQuick 2.4
587+import Ubuntu.Components 1.2
588+
589+Item {
590+ id: headerRow
591+
592+ height: units.gu(7)
593+
594+ Row {
595+ id: iconContainer
596+
597+ anchors.centerIn: parent
598+
599+ ActionIcon {
600+ width: units.gu(5.5)
601+ height: units.gu(4)
602+ iconWidth: units.gu(4)
603+ iconSource: Qt.resolvedUrl("../graphics/WorldClock_Placeholder.svg")
604+ onClicked: listview.currentIndex = 0
605+ }
606+
607+ ActionIcon {
608+ width: units.gu(5.5)
609+ height: units.gu(4)
610+ iconWidth: units.gu(4)
611+ iconSource: Qt.resolvedUrl("../graphics/Stopwatch_Placeholder.svg")
612+ onClicked: listview.currentIndex = 1
613+ }
614+ }
615+
616+ Rectangle {
617+ id: outerProgressRectangle
618+ anchors {
619+ left: iconContainer.left
620+ right: iconContainer.right
621+ top: iconContainer.bottom
622+ }
623+ height: units.gu(0.3)
624+ color: UbuntuColors.lightGrey
625+
626+ Rectangle {
627+ height: parent.height
628+ x: listview.currentIndex == 0 ? 0 : parent.width-width
629+ width: units.gu(5.5)
630+ color: UbuntuColors.orange
631+ Behavior on x {
632+ UbuntuNumberAnimation {}
633+ }
634+ }
635+ }
636+
637+ ActionIcon {
638+ id: settingsIcon
639+ objectName: "settingsIcon"
640+
641+ anchors {
642+ verticalCenter: parent.verticalCenter
643+ right: parent.right
644+ rightMargin: units.gu(2)
645+ }
646+
647+ iconName: "settings"
648+
649+ onClicked: {
650+ mainStack.push(Qt.resolvedUrl("../alarm/AlarmSettingsPage.qml"))
651+ }
652+ }
653+}
654
655=== modified file 'app/graphics/CMakeLists.txt'
656--- app/graphics/CMakeLists.txt 2015-08-11 16:05:15 +0000
657+++ app/graphics/CMakeLists.txt 2015-08-20 20:43:05 +0000
658@@ -7,6 +7,8 @@
659 Second_Hand@27.png
660 select-none.svg
661 select.svg
662+ Stopwatch_Placeholder.svg
663+ WorldClock_Placeholder.svg
664 )
665
666 # make the files visible in the qtcreator tree
667
668=== added file 'app/graphics/Stopwatch_Placeholder.svg'
669--- app/graphics/Stopwatch_Placeholder.svg 1970-01-01 00:00:00 +0000
670+++ app/graphics/Stopwatch_Placeholder.svg 2015-08-20 20:43:05 +0000
671@@ -0,0 +1,19 @@
672+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
673+<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
674+ <!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
675+ <title>Placeholder Icons</title>
676+ <desc>Created with Sketch.</desc>
677+ <defs></defs>
678+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
679+ <g id="Placeholder-Icons" sketch:type="MSArtboardGroup" stroke="#5B5B5B">
680+ <g id="Timer-+-Stopwatch-+-Clock-icon" sketch:type="MSLayerGroup" transform="translate(19.000000, 17.000000)">
681+ <g id="Stopwatch" transform="translate(3.000000, 0.000000)" sketch:type="MSShapeGroup">
682+ <circle id="Oval-125-Copy" stroke-width="3" cx="28.5" cy="37.5" r="28.5"></circle>
683+ <path d="M22,1 L34.0300293,1.00149091" id="Line-Copy-3" stroke-width="5" stroke-linecap="square"></path>
684+ <path d="M26,6 L30.0300293,6.00149091" id="Line-Copy-4" stroke-width="5" stroke-linecap="square"></path>
685+ <path d="M34.6896914,37.7022985 L34.6896914,22.495895" id="Line-Copy-5" stroke-width="3" stroke-linecap="square" transform="translate(34.689691, 30.099097) rotate(-315.000000) translate(-34.689691, -30.099097) "></path>
686+ </g>
687+ </g>
688+ </g>
689+ </g>
690+</svg>
691\ No newline at end of file
692
693=== added file 'app/graphics/WorldClock_Placeholder.svg'
694--- app/graphics/WorldClock_Placeholder.svg 1970-01-01 00:00:00 +0000
695+++ app/graphics/WorldClock_Placeholder.svg 2015-08-20 20:43:05 +0000
696@@ -0,0 +1,22 @@
697+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
698+<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
699+ <!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
700+ <title>Placeholder Icons</title>
701+ <desc>Created with Sketch.</desc>
702+ <defs></defs>
703+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
704+ <g id="Placeholder-Icons" sketch:type="MSArtboardGroup">
705+ <g id="Timer-+-Stopwatch-+-Clock-icon" sketch:type="MSLayerGroup" transform="translate(19.000000, 17.000000)">
706+ <g id="Clock-icon" transform="translate(0.000000, 5.000000)" sketch:type="MSShapeGroup">
707+ <path d="M19.7838596,0 C2.47304842,0 0,2.48317111 0,19.8659897 L0,37.1340103 C0,54.5167567 2.47304842,57 19.7838596,57 L41.2161404,57 C58.5269504,57 61,54.5167567 61,37.1340103 L61,19.8659897 C61,2.48317111 58.5269504,0 41.2161404,0 L19.7838596,0 L19.7838596,0 Z" id="rect4158" stroke="#5B5B5B" stroke-width="3"></path>
708+ <g id="Hands" transform="translate(17.632812, 16.884454)">
709+ <path d="M0.026502832,4.16418529 L12.8671875,11.6155462" id="path4219" stroke="#5B5B5B" stroke-width="3"></path>
710+ <path d="M12.8671875,11.6155462 L32.7118814,0.099807479" id="path4231" stroke="#5B5B5B" stroke-width="2"></path>
711+ <ellipse id="path4221" fill="#5B5B5B" cx="12.8570867" cy="10.6155882" rx="4.37271174" ry="4.39499998"></ellipse>
712+ <path d="M12.5,11.1155462 L12.5,31.7331933" id="path4223" stroke="#5B5B5B"></path>
713+ </g>
714+ </g>
715+ </g>
716+ </g>
717+ </g>
718+</svg>
719\ No newline at end of file
720
721=== added directory 'app/stopwatch'
722=== added file 'app/stopwatch/CMakeLists.txt'
723--- app/stopwatch/CMakeLists.txt 1970-01-01 00:00:00 +0000
724+++ app/stopwatch/CMakeLists.txt 2015-08-20 20:43:05 +0000
725@@ -0,0 +1,11 @@
726+set(STOPWATCH_QML_JS_FILES
727+ LapListView.qml
728+ StopwatchFace.qml
729+ StopwatchPage.qml
730+ StopwatchUtils.qml
731+)
732+
733+# make the files visible in the qtcreator tree
734+add_custom_target(ubuntu-clock-app_stopwatch_QMlFiles ALL SOURCES ${STOPWATCH_QML_JS_FILES})
735+
736+install(FILES ${STOPWATCH_QML_JS_FILES} DESTINATION ${UBUNTU-CLOCK_APP_DIR}/stopwatch)
737
738=== added file 'app/stopwatch/LapListView.qml'
739--- app/stopwatch/LapListView.qml 1970-01-01 00:00:00 +0000
740+++ app/stopwatch/LapListView.qml 2015-08-20 20:43:05 +0000
741@@ -0,0 +1,140 @@
742+/*
743+ * Copyright (C) 2015 Canonical Ltd
744+ *
745+ * This file is part of Ubuntu Clock App
746+ *
747+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
748+ * it under the terms of the GNU General Public License version 3 as
749+ * published by the Free Software Foundation.
750+ *
751+ * Ubuntu Clock App is distributed in the hope that it will be useful,
752+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
753+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
754+ * GNU General Public License for more details.
755+ *
756+ * You should have received a copy of the GNU General Public License
757+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
758+ */
759+
760+import QtQuick 2.4
761+import QtQuick.Layouts 1.1
762+import Ubuntu.Components 1.2
763+
764+ListView {
765+ id: lapListView
766+
767+ clip: true
768+
769+ StopwatchUtils {
770+ id: stopwatchUtils
771+ }
772+
773+ header: ListItem {
774+ visible: count !== 0
775+ Row {
776+ anchors {
777+ left: parent.left
778+ right: parent.right
779+ verticalCenter: parent.verticalCenter
780+ margins: units.gu(2)
781+ }
782+
783+ Label {
784+ // #TRANSLATORS: This refers to the stopwatch lap and is shown as a header where space is limited. Constrain
785+ // translation length to a few characters.
786+ text: i18n.tr("Lap")
787+ width: parent.width / 7
788+ elide: Text.ElideRight
789+ font.weight: Font.DemiBold
790+ horizontalAlignment: Text.AlignHCenter
791+ }
792+
793+ Label {
794+ width: 3 * parent.width / 7
795+ elide: Text.ElideRight
796+ text: i18n.tr("Lap Time")
797+ font.weight: Font.DemiBold
798+ horizontalAlignment: Text.AlignHCenter
799+ }
800+
801+ Label {
802+ width: 3 * parent.width / 7
803+ elide: Text.ElideRight
804+ text: i18n.tr("Total Time")
805+ font.weight: Font.DemiBold
806+ horizontalAlignment: Text.AlignHCenter
807+ }
808+ }
809+ }
810+
811+ displaced: Transition {
812+ UbuntuNumberAnimation {
813+ property: "y"
814+ duration: UbuntuAnimation.BriskDuration
815+ }
816+ }
817+
818+ delegate: ListItem {
819+ divider.visible: true
820+ leadingActions: ListItemActions {
821+ actions: [
822+ Action {
823+ iconName: "delete"
824+ onTriggered: {
825+ lapHistory.removeLap(index)
826+ }
827+ }
828+ ]
829+ }
830+
831+ Row {
832+ anchors {
833+ left: parent.left
834+ right: parent.right
835+ verticalCenter: parent.verticalCenter
836+ margins: units.gu(2)
837+ }
838+
839+ Label {
840+ color: UbuntuColors.midAubergine
841+ text: "#%1".arg(Number(count - index).toLocaleString(Qt.locale(), "f", 0))
842+ width: parent.width / 7
843+ horizontalAlignment: Text.AlignHCenter
844+ }
845+
846+ Item {
847+ width: 3 * parent.width / 7
848+ height: childrenRect.height
849+ Row {
850+ anchors.horizontalCenter: parent.horizontalCenter
851+ Label {
852+ text: stopwatchUtils.lapTimeToString(model.laptime) + "."
853+ }
854+ Label {
855+ fontSize: "x-small"
856+ text: stopwatchUtils.millisToString(model.laptime)
857+ anchors.bottom: parent.bottom
858+ anchors.bottomMargin: units.dp(1)
859+ }
860+ }
861+ }
862+
863+ Item {
864+ width: 3 * parent.width / 7
865+ height: childrenRect.height
866+ Row {
867+ anchors.horizontalCenter: parent.horizontalCenter
868+ Label {
869+ text: stopwatchUtils.lapTimeToString(model.totaltime) + "."
870+ }
871+ Label {
872+ fontSize: "x-small"
873+ text: stopwatchUtils.millisToString(model.totaltime)
874+ anchors.bottom: parent.bottom
875+ anchors.bottomMargin: units.dp(1)
876+ }
877+ }
878+ }
879+ }
880+ }
881+}
882
883=== added file 'app/stopwatch/StopwatchFace.qml'
884--- app/stopwatch/StopwatchFace.qml 1970-01-01 00:00:00 +0000
885+++ app/stopwatch/StopwatchFace.qml 2015-08-20 20:43:05 +0000
886@@ -0,0 +1,61 @@
887+/*
888+ * Copyright (C) 2015 Canonical Ltd
889+ *
890+ * This file is part of Ubuntu Clock App
891+ *
892+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
893+ * it under the terms of the GNU General Public License version 3 as
894+ * published by the Free Software Foundation.
895+ *
896+ * Ubuntu Clock App is distributed in the hope that it will be useful,
897+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
898+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
899+ * GNU General Public License for more details.
900+ *
901+ * You should have received a copy of the GNU General Public License
902+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
903+ */
904+
905+import QtQuick 2.4
906+import Ubuntu.Components 1.2
907+import "../components"
908+
909+ClockCircle {
910+ id: outerCirle
911+
912+ // Property to hold the total time (in milliseconds)
913+ property int milliseconds: 0
914+
915+ isOuter: true
916+ width: units.gu(32)
917+
918+ StopwatchUtils {
919+ id: stopwatchUtils
920+ }
921+
922+ ClockCircle {
923+ id: innerCircle
924+
925+ width: units.gu(23)
926+ anchors.centerIn: parent
927+ }
928+
929+ Column {
930+ id: text
931+
932+ anchors.centerIn: parent
933+
934+ Label {
935+ text: stopwatchUtils.millisToTimeString(milliseconds, false, true)
936+ font.pixelSize: units.dp(34)
937+ color: UbuntuColors.midAubergine
938+ }
939+
940+ Label {
941+ text: stopwatchUtils.millisToString(milliseconds)
942+ font.pixelSize: units.dp(18)
943+ color: UbuntuColors.midAubergine
944+ anchors.horizontalCenter: parent.horizontalCenter
945+ }
946+ }
947+}
948
949=== added file 'app/stopwatch/StopwatchPage.qml'
950--- app/stopwatch/StopwatchPage.qml 1970-01-01 00:00:00 +0000
951+++ app/stopwatch/StopwatchPage.qml 2015-08-20 20:43:05 +0000
952@@ -0,0 +1,169 @@
953+/*
954+ * Copyright (C) 2015 Canonical Ltd
955+ *
956+ * This file is part of Ubuntu Clock App
957+ *
958+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
959+ * it under the terms of the GNU General Public License version 3 as
960+ * published by the Free Software Foundation.
961+ *
962+ * Ubuntu Clock App is distributed in the hope that it will be useful,
963+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
964+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
965+ * GNU General Public License for more details.
966+ *
967+ * You should have received a copy of the GNU General Public License
968+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
969+ */
970+
971+import QtQuick 2.4
972+import Ubuntu.Components 1.2
973+import Stopwatch.LapHistory 1.0
974+
975+Item {
976+ id: _stopwatchPage
977+ objectName: "stopwatchPage"
978+
979+ property date startTime: new Date()
980+ property date snapshot: startTime
981+ property bool running: false
982+
983+ property int timeDiff: snapshot - startTime
984+ property int oldDiff: 0
985+
986+ property int totalTimeDiff: timeDiff + oldDiff
987+
988+ Component.onCompleted: {
989+ console.log("[LOG]: Stopwatch Page Loaded")
990+ }
991+
992+ function start() {
993+ startTime = new Date()
994+ snapshot = startTime
995+ running = true
996+ }
997+
998+ function stop() {
999+ oldDiff += timeDiff
1000+ startTime = new Date()
1001+ snapshot = startTime
1002+ running = false
1003+ }
1004+
1005+ function update() {
1006+ snapshot = new Date()
1007+ }
1008+
1009+ function clear() {
1010+ oldDiff = 0
1011+ startTime = new Date()
1012+ snapshot = startTime
1013+ lapHistory.clear()
1014+ }
1015+
1016+ Timer {
1017+ id: refreshTimer
1018+ interval: 45
1019+ repeat: true
1020+ running: _stopwatchPage.running
1021+ onTriggered: {
1022+ _stopwatchPage.update()
1023+ }
1024+ }
1025+
1026+ StopwatchFace {
1027+ id: stopwatch
1028+ objectName: "stopwatch"
1029+
1030+ milliseconds: _stopwatchPage.totalTimeDiff
1031+
1032+ anchors {
1033+ top: parent.top
1034+ topMargin: units.gu(2)
1035+ horizontalCenter: parent.horizontalCenter
1036+ }
1037+ }
1038+
1039+ Row {
1040+ id: buttonRow
1041+
1042+ spacing: units.gu(2)
1043+ anchors {
1044+ top: stopwatch.bottom
1045+ topMargin: units.gu(3)
1046+ left: parent.left
1047+ right: parent.right
1048+ margins: units.gu(2)
1049+ }
1050+
1051+ Button {
1052+ id: stopButton
1053+ width: oldDiff !== 0 || running ? (parent.width - parent.spacing) / 2 : parent.width
1054+ color: !_stopwatchPage.running ? UbuntuColors.green : UbuntuColors.red
1055+ text: _stopwatchPage.running ? i18n.tr("Stop") : (oldDiff === 0 ? i18n.tr("Start") : i18n.tr("Resume"))
1056+ onClicked: {
1057+ if (_stopwatchPage.running) {
1058+ _stopwatchPage.stop()
1059+ } else {
1060+ _stopwatchPage.start()
1061+ }
1062+ }
1063+ Behavior on width {
1064+ UbuntuNumberAnimation{
1065+ duration: UbuntuAnimation.BriskDuration
1066+ }
1067+ }
1068+ }
1069+
1070+ Button {
1071+ id: lapButton
1072+ text: _stopwatchPage.running ? i18n.tr("Lap") : i18n.tr("Clear")
1073+ width: oldDiff !== 0 || running ? (parent.width - parent.spacing) / 2 : 0
1074+ strokeColor: UbuntuColors.lightGrey
1075+ visible: oldDiff !== 0 || running
1076+ onClicked: {
1077+ if (_stopwatchPage.running) {
1078+ _stopwatchPage.update()
1079+ lapHistory.addLap(_stopwatchPage.totalTimeDiff)
1080+ } else {
1081+ _stopwatchPage.clear()
1082+ }
1083+ }
1084+ Behavior on width {
1085+ UbuntuNumberAnimation{
1086+ duration: UbuntuAnimation.BriskDuration
1087+ }
1088+ }
1089+ }
1090+ }
1091+
1092+ MouseArea {
1093+ anchors {
1094+ top: buttonRow.bottom
1095+ bottom: parent.bottom
1096+ left: parent.left
1097+ right: parent.right
1098+ topMargin: units.gu(1)
1099+ }
1100+
1101+ preventStealing: true
1102+
1103+ Loader {
1104+ id: lapListViewLoader
1105+ anchors.fill: parent
1106+ sourceComponent: !_stopwatchPage.running && _stopwatchPage.totalTimeDiff == 0 ? undefined : lapListViewComponent
1107+ }
1108+ }
1109+
1110+ LapHistory {
1111+ id: lapHistory
1112+ }
1113+
1114+ Component {
1115+ id: lapListViewComponent
1116+ LapListView {
1117+ id: lapListView
1118+ model: lapHistory
1119+ }
1120+ }
1121+}
1122
1123=== added file 'app/stopwatch/StopwatchUtils.qml'
1124--- app/stopwatch/StopwatchUtils.qml 1970-01-01 00:00:00 +0000
1125+++ app/stopwatch/StopwatchUtils.qml 2015-08-20 20:43:05 +0000
1126@@ -0,0 +1,73 @@
1127+/*
1128+ * Copyright (C) 2015 Canonical Ltd
1129+ *
1130+ * This file is part of Ubuntu Clock App
1131+ *
1132+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
1133+ * it under the terms of the GNU General Public License version 3 as
1134+ * published by the Free Software Foundation.
1135+ *
1136+ * Ubuntu Clock App is distributed in the hope that it will be useful,
1137+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1138+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1139+ * GNU General Public License for more details.
1140+ *
1141+ * You should have received a copy of the GNU General Public License
1142+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1143+ */
1144+
1145+import QtQuick 2.4
1146+import Ubuntu.Components 1.2
1147+
1148+/*
1149+ Qt Object containing a collection of useful stopwatch functions
1150+*/
1151+QtObject {
1152+ id: stopwatchUtils
1153+
1154+ // Function to return only the milliseconds
1155+ function millisToString(millis) {
1156+ return addZeroPrefix(millis % 1000, 3)
1157+ }
1158+
1159+ // Function to break down time (milliseconds) to hours, minutes and seconds
1160+ function millisToTimeString(millis, showMilliseconds, showHours) {
1161+ var hours, minutes, seconds
1162+
1163+ // Break down total time (milliseconds) to hours, minutes and seconds
1164+ seconds = Math.floor(millis / 1000) % 60;
1165+ minutes = Math.floor(millis / 1000 / 60) % 60
1166+ hours = Math.floor(millis / 1000 / 60 / 60)
1167+
1168+ // Build the time string
1169+ var timeString = ""
1170+
1171+ if (showHours) {
1172+ timeString += addZeroPrefix(hours, 2) + ":"
1173+ }
1174+
1175+ timeString += addZeroPrefix(minutes, 2) + ":"
1176+ timeString += addZeroPrefix(seconds, 2)
1177+
1178+ if (showMilliseconds) {
1179+ timeString += "." + millisToString(millis)
1180+ }
1181+
1182+ return timeString
1183+ }
1184+
1185+ // Function to add zero prefix if necessary.
1186+ function addZeroPrefix (str, totalLength) {
1187+ return ("00000" + str).slice(-totalLength)
1188+ }
1189+
1190+ // Function to return lap time as a string
1191+ function lapTimeToString(millis) {
1192+ var hours = hours = Math.floor(millis / 1000 / 60 / 60)
1193+ if (hours > 0) {
1194+ return millisToTimeString(millis, false, true)
1195+ } else {
1196+ return millisToTimeString(millis, false, false)
1197+ }
1198+ }
1199+}
1200
1201=== modified file 'app/ubuntu-clock-app.qml'
1202--- app/ubuntu-clock-app.qml 2015-07-15 22:31:52 +0000
1203+++ app/ubuntu-clock-app.qml 2015-08-20 20:43:05 +0000
1204@@ -20,7 +20,6 @@
1205 import DateTime 1.0
1206 import U1db 1.0 as U1db
1207 import Ubuntu.Components 1.2
1208-import "clock"
1209 import "components"
1210
1211 MainView {
1212@@ -89,7 +88,7 @@
1213 Reload the alarm model when the clock app gains focus to refresh
1214 the alarm page UI in the case of alarm notifications.
1215 */
1216- if(applicationState && !clockPage.isColdStart) {
1217+ if(applicationState && !mainPage.isColdStart) {
1218 alarmModelLoader.source = ""
1219 alarmModelLoader.source = Qt.resolvedUrl("alarm/AlarmModelComponent.qml")
1220 }
1221@@ -98,10 +97,10 @@
1222 PageStack {
1223 id: mainStack
1224
1225- Component.onCompleted: push(clockPage)
1226+ Component.onCompleted: push(mainPage)
1227
1228- ClockPage {
1229- id: clockPage
1230+ MainPage {
1231+ id: mainPage
1232
1233 Loader {
1234 id: alarmModelLoader
1235@@ -113,26 +112,26 @@
1236 clock page title. This will then set the correct window title on
1237 the desktop.
1238
1239- title: "Clock"
1240- */
1241-
1242- /*
1243- Create a new Date() object and pass the date, month, year, hour, minute
1244- and second received from the DateTime plugin manually to ensure the
1245- timezone info is set correctly.
1246-
1247- Javascript Month is 0-11 while QDateTime month is 1-12. Hence the -1
1248- is required.
1249- */
1250-
1251- /*
1252- FIXME: When the upstream QT bug at
1253+ title: i18n.tr("Clock")
1254+ */
1255+
1256+ /*
1257+ Create a new Date() object and pass the date, month, year, hour, minute
1258+ and second received from the DateTime plugin manually to ensure the
1259+ timezone info is set correctly.
1260+
1261+ Javascript Month is 0-11 while QDateTime month is 1-12. Hence the -1
1262+ is required.
1263+ */
1264+
1265+ /*
1266+ #FIXME: When the upstream QT bug at
1267 https://bugreports.qt-project.org/browse/QTBUG-40275 is fixed it will be
1268 possible to receive a datetime object directly instead of using this hack.
1269 */
1270
1271 alarmModel: alarmModelLoader.item
1272- bottomEdgeEnabled: alarmModelLoader.status === Loader.Ready && alarmModelLoader.item.isReady
1273+ bottomEdgeEnabled: alarmModelLoader.status === Loader.Ready && alarmModelLoader.item.isReady && isClockPage
1274 clockTime: new Date
1275 (
1276 localTimeSource.localDateString.split(":")[0],
1277
1278=== modified file 'app/worldclock/AddWorldCityButton.qml'
1279--- app/worldclock/AddWorldCityButton.qml 2015-08-14 05:34:49 +0000
1280+++ app/worldclock/AddWorldCityButton.qml 2015-08-20 20:43:05 +0000
1281@@ -24,7 +24,7 @@
1282 id: addWorldCityButton
1283
1284 width: parent.width
1285- height: _addButton.height
1286+ height: _addButton.height + units.gu(4)
1287
1288 Label {
1289 text: i18n.tr("Add")
1290@@ -32,7 +32,7 @@
1291 anchors {
1292 right: _addButton.left
1293 rightMargin: units.gu(1)
1294- verticalCenter: parent.verticalCenter
1295+ verticalCenter: _addButton.verticalCenter
1296 }
1297 }
1298
1299@@ -41,7 +41,11 @@
1300
1301 isOuter: true
1302 width: units.gu(5)
1303- anchors.horizontalCenter: parent.horizontalCenter
1304+ anchors {
1305+ horizontalCenter: parent.horizontalCenter
1306+ top: parent.top
1307+ topMargin: units.gu(1)
1308+ }
1309
1310 ClockCircle {
1311 width: units.gu(3.5)
1312@@ -63,7 +67,7 @@
1313 anchors {
1314 left: _addButton.right
1315 leftMargin: units.gu(1)
1316- verticalCenter: parent.verticalCenter
1317+ verticalCenter: _addButton.verticalCenter
1318 }
1319 }
1320
1321
1322=== modified file 'app/worldclock/UserWorldCityList.qml'
1323--- app/worldclock/UserWorldCityList.qml 2015-08-14 05:34:49 +0000
1324+++ app/worldclock/UserWorldCityList.qml 2015-08-20 20:43:05 +0000
1325@@ -21,11 +21,16 @@
1326 import U1db 1.0 as U1db
1327 import Ubuntu.Components 1.2
1328
1329-Column {
1330+ListView {
1331 id: worldCityColumn
1332-
1333- width: parent.width
1334- height: childrenRect.height
1335+ objectName: "userWorldCityRepeater"
1336+
1337+ clip: true
1338+ anchors.fill: parent
1339+
1340+ onFlickStarted: {
1341+ forceActiveFocus()
1342+ }
1343
1344 // U1db Index to index all documents storing the world city details
1345 U1db.Index {
1346@@ -51,93 +56,89 @@
1347 results: worldCityQuery.results
1348 }
1349
1350- Repeater {
1351- id: userWorldCityRepeater
1352- objectName: "userWorldCityRepeater"
1353-
1354- property var _currentSwipedItem: null
1355-
1356- function _updateSwipeState(item)
1357- {
1358- if (item.swipping) {
1359- return
1360- }
1361-
1362- if (item.swipeState !== "Normal") {
1363- if (userWorldCityRepeater._currentSwipedItem !== item) {
1364- if (userWorldCityRepeater._currentSwipedItem) {
1365- userWorldCityRepeater._currentSwipedItem.resetSwipe()
1366- }
1367- userWorldCityRepeater._currentSwipedItem = item
1368- }
1369- } else if (item.swipeState !== "Normal"
1370- && userWorldCityRepeater._currentSwipedItem === item) {
1371- userWorldCityRepeater._currentSwipedItem = null
1372- }
1373- }
1374-
1375- model: u1dbModel
1376-
1377- delegate: UserWorldCityDelegate {
1378- id: userWorldCityDelegate
1379- objectName: "userWorldCityItem" + index
1380-
1381- property var removalAnimation
1382-
1383- function remove() {
1384- removalAnimation.start()
1385- }
1386-
1387- onSwippingChanged: {
1388- userWorldCityRepeater._updateSwipeState(userWorldCityDelegate)
1389- }
1390-
1391- onSwipeStateChanged: {
1392- userWorldCityRepeater._updateSwipeState(userWorldCityDelegate)
1393- }
1394-
1395- leftSideAction: Action {
1396- iconName: "delete"
1397- text: i18n.tr("Delete")
1398- onTriggered: {
1399- userWorldCityDelegate.remove()
1400- }
1401- }
1402-
1403- ListView.onRemove: ScriptAction {
1404- script: {
1405- if (userWorldCityRepeater._currentSwipedItem
1406- === userWorldCityDelegate) {
1407- userWorldCityRepeater._currentSwipedItem = null
1408- }
1409- }
1410- }
1411-
1412- removalAnimation: SequentialAnimation {
1413- alwaysRunToEnd: true
1414-
1415- PropertyAction {
1416- target: userWorldCityDelegate
1417- property: "ListView.delayRemove"
1418- value: true
1419- }
1420-
1421- UbuntuNumberAnimation {
1422- target: userWorldCityDelegate
1423- property: "height"
1424- to: 0
1425- }
1426-
1427- PropertyAction {
1428- target: userWorldCityDelegate
1429- property: "ListView.delayRemove"
1430- value: false
1431- }
1432-
1433- ScriptAction {
1434- script: clockDB.deleteDoc(worldCityQuery.documents[index])
1435- }
1436- }
1437- }
1438- }
1439+ property var _currentSwipedItem: null
1440+
1441+ function _updateSwipeState(item)
1442+ {
1443+ if (item.swipping) {
1444+ return
1445+ }
1446+
1447+ if (item.swipeState !== "Normal") {
1448+ if (worldCityColumn._currentSwipedItem !== item) {
1449+ if (worldCityColumn._currentSwipedItem) {
1450+ worldCityColumn._currentSwipedItem.resetSwipe()
1451+ }
1452+ worldCityColumn._currentSwipedItem = item
1453+ }
1454+ } else if (item.swipeState !== "Normal"
1455+ && worldCityColumn._currentSwipedItem === item) {
1456+ worldCityColumn._currentSwipedItem = null
1457+ }
1458+ }
1459+
1460+ model: u1dbModel
1461+
1462+ delegate: UserWorldCityDelegate {
1463+ id: userWorldCityDelegate
1464+ objectName: "userWorldCityItem" + index
1465+
1466+ property var removalAnimation
1467+
1468+ function remove() {
1469+ removalAnimation.start()
1470+ }
1471+
1472+ onSwippingChanged: {
1473+ worldCityColumn._updateSwipeState(userWorldCityDelegate)
1474+ }
1475+
1476+ onSwipeStateChanged: {
1477+ worldCityColumn._updateSwipeState(userWorldCityDelegate)
1478+ }
1479+
1480+ leftSideAction: Action {
1481+ iconName: "delete"
1482+ text: i18n.tr("Delete")
1483+ onTriggered: {
1484+ userWorldCityDelegate.remove()
1485+ }
1486+ }
1487+
1488+ ListView.onRemove: ScriptAction {
1489+ script: {
1490+ if (worldCityColumn._currentSwipedItem
1491+ === userWorldCityDelegate) {
1492+ worldCityColumn._currentSwipedItem = null
1493+ }
1494+ }
1495+ }
1496+
1497+ removalAnimation: SequentialAnimation {
1498+ alwaysRunToEnd: true
1499+
1500+ PropertyAction {
1501+ target: userWorldCityDelegate
1502+ property: "ListView.delayRemove"
1503+ value: true
1504+ }
1505+
1506+ UbuntuNumberAnimation {
1507+ target: userWorldCityDelegate
1508+ property: "height"
1509+ to: 0
1510+ }
1511+
1512+ PropertyAction {
1513+ target: userWorldCityDelegate
1514+ property: "ListView.delayRemove"
1515+ value: false
1516+ }
1517+
1518+ ScriptAction {
1519+ script: clockDB.deleteDoc(worldCityQuery.documents[index])
1520+ }
1521+ }
1522+ }
1523+
1524 }
1525
1526=== modified file 'backend/CMakeLists.txt'
1527--- backend/CMakeLists.txt 2015-07-16 21:02:18 +0000
1528+++ backend/CMakeLists.txt 2015-08-20 20:43:05 +0000
1529@@ -34,6 +34,12 @@
1530 modules/GeoLocation/geolocation.cpp
1531 )
1532
1533+set(
1534+ stopwatchlaphistory_SRCS
1535+ modules/Stopwatch/LapHistory/backend.cpp
1536+ modules/Stopwatch/LapHistory/history.cpp
1537+)
1538+
1539 add_library(timezone MODULE
1540 ${timezone_SRCS}
1541 )
1542@@ -50,6 +56,11 @@
1543 ${geolocation_SRCS}
1544 )
1545
1546+add_library(stopwatchlaphistory MODULE
1547+ ${stopwatchlaphistory_SRCS}
1548+)
1549+
1550+
1551 set_target_properties(timezone PROPERTIES
1552 LIBRARY_OUTPUT_DIRECTORY Timezone
1553 )
1554@@ -66,10 +77,15 @@
1555 LIBRARY_OUTPUT_DIRECTORY GeoLocation
1556 )
1557
1558+set_target_properties(stopwatchlaphistory PROPERTIES
1559+ LIBRARY_OUTPUT_DIRECTORY Stopwatch/LapHistory
1560+)
1561+
1562 qt5_use_modules(datetime Gui Qml Quick)
1563 qt5_use_modules(timezone Gui Qml Quick)
1564 qt5_use_modules(alarmsettings Gui Qml Quick DBus)
1565 qt5_use_modules(geolocation Gui Qml Quick)
1566+qt5_use_modules(stopwatchlaphistory Qml)
1567
1568 # Copy qmldir file to build dir for running in QtCreator
1569 add_custom_target(timezone-qmldir ALL
1570@@ -92,6 +108,12 @@
1571 DEPENDS ${QMLFILES}
1572 )
1573
1574+add_custom_target(stopwatchlaphistory-qmldir ALL
1575+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/modules/Stopwatch/LapHistory/qmldir ${CMAKE_CURRENT_BINARY_DIR}/Stopwatch/LapHistory
1576+ DEPENDS ${QMLFILES}
1577+)
1578+
1579+
1580 # Install plugin file
1581 install(TARGETS timezone DESTINATION ${MODULE_PATH}/Timezone/)
1582 install(FILES modules/Timezone/qmldir DESTINATION ${MODULE_PATH}/Timezone/)
1583@@ -104,3 +126,6 @@
1584
1585 install(TARGETS geolocation DESTINATION ${MODULE_PATH}/GeoLocation/)
1586 install(FILES modules/GeoLocation/qmldir DESTINATION ${MODULE_PATH}/GeoLocation/)
1587+
1588+install(TARGETS stopwatchlaphistory DESTINATION ${MODULE_PATH}/Stopwatch/LapHistory/)
1589+install(FILES modules/Stopwatch/LapHistory/qmldir DESTINATION ${MODULE_PATH}/Stopwatch/LapHistory/)
1590
1591=== added directory 'backend/modules/Stopwatch'
1592=== added directory 'backend/modules/Stopwatch/LapHistory'
1593=== added file 'backend/modules/Stopwatch/LapHistory/backend.cpp'
1594--- backend/modules/Stopwatch/LapHistory/backend.cpp 1970-01-01 00:00:00 +0000
1595+++ backend/modules/Stopwatch/LapHistory/backend.cpp 2015-08-20 20:43:05 +0000
1596@@ -0,0 +1,34 @@
1597+/*
1598+ * Copyright (C) 2015 Canonical Ltd
1599+ *
1600+ * This file is part of Ubuntu Clock App
1601+ *
1602+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
1603+ * it under the terms of the GNU General Public License version 3 as
1604+ * published by the Free Software Foundation.
1605+ *
1606+ * Ubuntu Clock App is distributed in the hope that it will be useful,
1607+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1608+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1609+ * GNU General Public License for more details.
1610+ *
1611+ * You should have received a copy of the GNU General Public License
1612+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1613+ */
1614+
1615+#include <QtQml>
1616+#include <QtQml/QQmlContext>
1617+#include "backend.h"
1618+#include "history.h"
1619+
1620+void BackendPlugin::registerTypes(const char *uri)
1621+{
1622+ Q_ASSERT(uri == QLatin1String("Stopwatch.LapHistory"));
1623+
1624+ qmlRegisterType<LapHistory>(uri, 1, 0, "LapHistory");
1625+}
1626+
1627+void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
1628+{
1629+ QQmlExtensionPlugin::initializeEngine(engine, uri);
1630+}
1631
1632=== added file 'backend/modules/Stopwatch/LapHistory/backend.h'
1633--- backend/modules/Stopwatch/LapHistory/backend.h 1970-01-01 00:00:00 +0000
1634+++ backend/modules/Stopwatch/LapHistory/backend.h 2015-08-20 20:43:05 +0000
1635@@ -0,0 +1,35 @@
1636+/*
1637+ * Copyright (C) 2015 Canonical Ltd
1638+ *
1639+ * This file is part of Ubuntu Clock App
1640+ *
1641+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
1642+ * it under the terms of the GNU General Public License version 3 as
1643+ * published by the Free Software Foundation.
1644+ *
1645+ * Ubuntu Clock App is distributed in the hope that it will be useful,
1646+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1647+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1648+ * GNU General Public License for more details.
1649+ *
1650+ * You should have received a copy of the GNU General Public License
1651+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1652+ */
1653+
1654+#ifndef BACKEND_PLUGIN_H
1655+#define BACKEND_PLUGIN_H
1656+
1657+#include <QtQml/QQmlEngine>
1658+#include <QtQml/QQmlExtensionPlugin>
1659+
1660+class BackendPlugin : public QQmlExtensionPlugin
1661+{
1662+ Q_OBJECT
1663+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
1664+
1665+public:
1666+ void registerTypes(const char *uri);
1667+ void initializeEngine(QQmlEngine *engine, const char *uri);
1668+};
1669+#endif // BACKEND_PLUGIN_H
1670+
1671
1672=== added file 'backend/modules/Stopwatch/LapHistory/history.cpp'
1673--- backend/modules/Stopwatch/LapHistory/history.cpp 1970-01-01 00:00:00 +0000
1674+++ backend/modules/Stopwatch/LapHistory/history.cpp 2015-08-20 20:43:05 +0000
1675@@ -0,0 +1,97 @@
1676+/*
1677+ * Copyright (C) 2015 Canonical Ltd
1678+ *
1679+ * This file is part of Ubuntu Clock App
1680+ *
1681+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
1682+ * it under the terms of the GNU General Public License version 3 as
1683+ * published by the Free Software Foundation.
1684+ *
1685+ * Ubuntu Clock App is distributed in the hope that it will be useful,
1686+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1687+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1688+ * GNU General Public License for more details.
1689+ *
1690+ * You should have received a copy of the GNU General Public License
1691+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1692+ */
1693+
1694+#include "history.h"
1695+
1696+#include <QStandardPaths>
1697+#include <QDebug>
1698+
1699+LapHistory::LapHistory(QObject *parent) :
1700+ QAbstractListModel(parent),
1701+ /*
1702+ #FIXME: Change QStandardPaths::ConfigLocation to QStandardPaths::AppConfigLocation
1703+ when Ubuntu Touch moves over to Qt 5.5. AppConfigLocation will directly return
1704+ /home/phablet/.config/com.ubuntu.clock path.
1705+ */
1706+ m_settings(QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first() + "/com.ubuntu.clock/com.ubuntu.clock.conf", QSettings::IniFormat)
1707+{
1708+ qDebug() << "[LOG] Loading laps from " << m_settings.fileName();
1709+}
1710+
1711+int LapHistory::rowCount(const QModelIndex &parent) const
1712+{
1713+ /*
1714+ QT's models also handle tables and tree views, so the index is not just a
1715+ integer but consists of a parent, row and a column. Since we using a simple
1716+ list model, let's ignore the parent. Q_UNUSED(parent) gets rid of the
1717+ compiler warning about the unused variable.
1718+ */
1719+ Q_UNUSED(parent)
1720+
1721+ return m_settings.value("Stopwatch/laps").toList().count();
1722+}
1723+
1724+QVariant LapHistory::data(const QModelIndex &index, int role) const
1725+{
1726+ switch (role) {
1727+ case RoleTotalTime:
1728+ return m_settings.value("Stopwatch/laps").toList().at(index.row());
1729+ case RoleDiffToPrevious: {
1730+ int previous = 0;
1731+ if(index.row() != m_settings.value("Stopwatch/laps").toList().count() - 1)
1732+ {
1733+ previous = data(this->index(index.row() + 1), RoleTotalTime).toInt();
1734+ }
1735+ return m_settings.value("Stopwatch/laps").toList().at(index.row()).toInt() - previous;
1736+ }
1737+ }
1738+ return QVariant();
1739+}
1740+
1741+QHash<int, QByteArray> LapHistory::roleNames() const
1742+{
1743+ QHash< int, QByteArray> roles;
1744+ roles.insert(RoleTotalTime, "totaltime");
1745+ roles.insert(RoleDiffToPrevious, "laptime");
1746+ return roles;
1747+}
1748+
1749+void LapHistory::addLap(int timeDiff)
1750+{
1751+ QVariantList laps = m_settings.value("Stopwatch/laps").toList();
1752+ beginInsertRows(QModelIndex(), 0, 0);
1753+ laps.prepend(timeDiff);
1754+ m_settings.setValue("Stopwatch/laps", laps);
1755+ endInsertRows();
1756+}
1757+
1758+void LapHistory::removeLap(int lapIndex)
1759+{
1760+ QVariantList laps = m_settings.value("Stopwatch/laps").toList();
1761+ beginRemoveRows(QModelIndex(), lapIndex, lapIndex);
1762+ laps.removeAt(lapIndex);
1763+ m_settings.setValue("Stopwatch/laps", laps);
1764+ endRemoveRows();
1765+}
1766+
1767+void LapHistory::clear()
1768+{
1769+ beginResetModel();
1770+ m_settings.setValue("Stopwatch/laps", QVariantList());
1771+ endResetModel();
1772+}
1773
1774=== added file 'backend/modules/Stopwatch/LapHistory/history.h'
1775--- backend/modules/Stopwatch/LapHistory/history.h 1970-01-01 00:00:00 +0000
1776+++ backend/modules/Stopwatch/LapHistory/history.h 2015-08-20 20:43:05 +0000
1777@@ -0,0 +1,64 @@
1778+/*
1779+ * Copyright (C) 2015 Canonical Ltd
1780+ *
1781+ * This file is part of Ubuntu Clock App
1782+ *
1783+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
1784+ * it under the terms of the GNU General Public License version 3 as
1785+ * published by the Free Software Foundation.
1786+ *
1787+ * Ubuntu Clock App is distributed in the hope that it will be useful,
1788+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1789+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1790+ * GNU General Public License for more details.
1791+ *
1792+ * You should have received a copy of the GNU General Public License
1793+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1794+ */
1795+
1796+#ifndef HISTORY_H
1797+#define HISTORY_H
1798+
1799+#include <QAbstractListModel>
1800+#include <QSettings>
1801+
1802+class LapHistory : public QAbstractListModel
1803+{
1804+ Q_OBJECT
1805+
1806+public:
1807+ enum Role {
1808+ RoleTotalTime,
1809+ RoleDiffToPrevious
1810+ };
1811+
1812+ explicit LapHistory(QObject *parent = 0);
1813+
1814+ /*
1815+ Let's override the pure virtual functions (the ones marked as
1816+ "virtual" and have "= 0" in the end.
1817+ */
1818+ int rowCount(const QModelIndex &parent) const;
1819+ QVariant data(const QModelIndex &index, int role) const;
1820+
1821+ /*
1822+ As QML can't really deal with the Roles enum above, we need a mapping
1823+ between the enum and strings
1824+ */
1825+ QHash<int, QByteArray> roleNames() const override;
1826+
1827+public slots:
1828+ // Function to add a stopwatch lap
1829+ void addLap(int timeDiff);
1830+
1831+ // Function to remove a stopwatch lap
1832+ void removeLap(int lapIndex);
1833+
1834+ // Function to clear all stopwatch laps
1835+ void clear();
1836+
1837+private:
1838+ QSettings m_settings;
1839+};
1840+
1841+#endif // HISTORY_H
1842
1843=== added file 'backend/modules/Stopwatch/LapHistory/qmldir'
1844--- backend/modules/Stopwatch/LapHistory/qmldir 1970-01-01 00:00:00 +0000
1845+++ backend/modules/Stopwatch/LapHistory/qmldir 2015-08-20 20:43:05 +0000
1846@@ -0,0 +1,2 @@
1847+module Stopwatch.LapHistory
1848+plugin stopwatchlaphistory
1849
1850=== modified file 'debian/changelog'
1851--- debian/changelog 2015-08-16 20:53:03 +0000
1852+++ debian/changelog 2015-08-20 20:43:05 +0000
1853@@ -7,9 +7,11 @@
1854 * Fix default alarm time issue (LP: #1484926)
1855 * Translate city and country names after language switch (LP: #1477492)
1856 * Fix issue when unable to add city/country with apostrophes (LP: #1473074)
1857+ * Keep running stopwatch even when the clock or phone is turned off (LP: #1484942)
1858
1859 [Nekhelesh Ramananthan]
1860 * Increase the height of times in the alarm screen (LP: #1365428)
1861+ * Implement Stopwatch feature (LP: 1437313)
1862 * Fixed the confusing behavior of the confirmation button (LP: #1408015)
1863 * Added README.mergeproposal checklist to help with the review process.
1864 * Fix alarm interval information being inconsistent (LP: #1466000)
1865
1866=== modified file 'debian/control'
1867--- debian/control 2015-07-27 20:52:03 +0000
1868+++ debian/control 2015-08-20 20:43:05 +0000
1869@@ -10,6 +10,8 @@
1870 ubuntu-touch-sounds,
1871 suru-icon-theme | ubuntu-mobile-icons,
1872 qml-module-qttest,
1873+ qml-module-qtsysteminfo,
1874+ qml-module-qt-labs-settings,
1875 qtdeclarative5-u1db1.0,
1876 qtdeclarative5-qtmultimedia-plugin,
1877 qtdeclarative5-qtpositioning-plugin,
1878
1879=== modified file 'po/com.ubuntu.clock.pot'
1880--- po/com.ubuntu.clock.pot 2015-08-16 20:56:27 +0000
1881+++ po/com.ubuntu.clock.pot 2015-08-20 20:43:05 +0000
1882@@ -8,7 +8,7 @@
1883 msgstr ""
1884 "Project-Id-Version: \n"
1885 "Report-Msgid-Bugs-To: \n"
1886-"POT-Creation-Date: 2015-08-16 22:55+0200\n"
1887+"POT-Creation-Date: 2015-08-20 22:42+0200\n"
1888 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1889 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1890 "Language-Team: LANGUAGE <LL@li.org>\n"
1891@@ -18,13 +18,17 @@
1892 "Content-Transfer-Encoding: 8bit\n"
1893 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
1894
1895+#: ../app/MainPage.qml:47 ../app/alarm/AlarmUtils.qml:55
1896+msgid "No active alarms"
1897+msgstr ""
1898+
1899 #: ../app/alarm/AlarmLabel.qml:33 ../app/alarm/AlarmLabel.qml:71
1900 #: ../app/alarm/EditAlarmPage.qml:290
1901 msgid "Label"
1902 msgstr ""
1903
1904 #: ../app/alarm/AlarmList.qml:61 ../app/alarm/AlarmPage.qml:99
1905-#: ../app/worldclock/UserWorldCityList.qml:101
1906+#: ../app/worldclock/UserWorldCityList.qml:102
1907 msgid "Delete"
1908 msgstr ""
1909
1910@@ -120,10 +124,6 @@
1911 msgid "Daily"
1912 msgstr ""
1913
1914-#: ../app/alarm/AlarmUtils.qml:55
1915-msgid "No active alarms"
1916-msgstr ""
1917-
1918 #: ../app/alarm/AlarmUtils.qml:72
1919 #, qt-format
1920 msgid "Next Alarm %1"
1921@@ -160,15 +160,45 @@
1922 msgid "Delete alarm"
1923 msgstr ""
1924
1925-#: ../app/clock/ClockPage.qml:284
1926+#: ../app/clock/ClockPage.qml:225
1927 msgid "Retrieving location..."
1928 msgstr ""
1929
1930+#. TRANSLATORS: This refers to the stopwatch lap and is shown as a header where space is limited. Constrain
1931+#. translation length to a few characters.
1932+#: ../app/stopwatch/LapListView.qml:45 ../app/stopwatch/StopwatchPage.qml:120
1933+msgid "Lap"
1934+msgstr ""
1935+
1936+#: ../app/stopwatch/LapListView.qml:55
1937+msgid "Lap Time"
1938+msgstr ""
1939+
1940+#: ../app/stopwatch/LapListView.qml:63
1941+msgid "Total Time"
1942+msgstr ""
1943+
1944+#: ../app/stopwatch/StopwatchPage.qml:103
1945+msgid "Stop"
1946+msgstr ""
1947+
1948+#: ../app/stopwatch/StopwatchPage.qml:103
1949+msgid "Start"
1950+msgstr ""
1951+
1952+#: ../app/stopwatch/StopwatchPage.qml:103
1953+msgid "Resume"
1954+msgstr ""
1955+
1956+#: ../app/stopwatch/StopwatchPage.qml:120
1957+msgid "Clear"
1958+msgstr ""
1959+
1960 #: ../app/worldclock/AddWorldCityButton.qml:30
1961 msgid "Add"
1962 msgstr ""
1963
1964-#: ../app/worldclock/AddWorldCityButton.qml:61
1965+#: ../app/worldclock/AddWorldCityButton.qml:65
1966 #: ../app/worldclock/WorldCityList.qml:63
1967 msgid "City"
1968 msgstr ""
1969
1970=== modified file 'tests/unit/CMakeLists.txt'
1971--- tests/unit/CMakeLists.txt 2015-07-14 20:49:37 +0000
1972+++ tests/unit/CMakeLists.txt 2015-08-20 20:43:05 +0000
1973@@ -27,6 +27,7 @@
1974 declare_qml_test("AlarmSound" tst_alarmSound.qml)
1975 declare_qml_test("AlarmUtils" tst_alarmUtils.qml)
1976 declare_qml_test("WorldClock" tst_worldClock.qml)
1977+ declare_qml_test("StopwatchUtils" tst_stopwatchUtils.qml)
1978 else()
1979 if (NOT QMLTESTRUNNER_BIN)
1980 message(WARNING "Qml tests disabled: qmltestrunner not found")
1981@@ -42,6 +43,7 @@
1982 tst_alarmSound.qml
1983 tst_alarmUtils.qml
1984 tst_worldClock.qml
1985+ tst_stopwatchUtils.qml
1986 )
1987 add_custom_target(tst_QmlFiles ALL SOURCES ${QML_TST_FILES})
1988
1989
1990=== modified file 'tests/unit/MockClockApp.qml'
1991--- tests/unit/MockClockApp.qml 2015-08-14 05:34:49 +0000
1992+++ tests/unit/MockClockApp.qml 2015-08-20 20:43:05 +0000
1993@@ -20,8 +20,9 @@
1994 import DateTime 1.0
1995 import U1db 1.0 as U1db
1996 import Ubuntu.Components 1.2
1997+import "../../app"
1998+import "../../app/components"
1999 import "../../app/clock"
2000-import "../../app/components"
2001
2002 /*
2003 This file is meant to create a fake but fully fleshed clock app with its
2004@@ -69,10 +70,10 @@
2005 id: mainStack
2006 objectName: "pageStack"
2007
2008- Component.onCompleted: push(clockPage)
2009+ Component.onCompleted: push(mainPage)
2010
2011- ClockPage {
2012- id: clockPage
2013+ MainPage {
2014+ id: mainPage
2015
2016 Loader {
2017 id: alarmModelLoader
2018@@ -80,7 +81,7 @@
2019 }
2020
2021 alarmModel: alarmModelLoader.item
2022- bottomEdgeEnabled: alarmModelLoader.status === Loader.Ready
2023+ bottomEdgeEnabled: alarmModelLoader.status === Loader.Ready && alarmModelLoader.item.isReady && isClockPage
2024 clockTime: new Date
2025 (
2026 localTimeSource.localDateString.split(":")[0],
2027
2028=== added file 'tests/unit/tst_stopwatchUtils.qml'
2029--- tests/unit/tst_stopwatchUtils.qml 1970-01-01 00:00:00 +0000
2030+++ tests/unit/tst_stopwatchUtils.qml 2015-08-20 20:43:05 +0000
2031@@ -0,0 +1,79 @@
2032+/*
2033+ * Copyright (C) 2015 Canonical Ltd
2034+ *
2035+ * This file is part of Ubuntu Clock App
2036+ *
2037+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
2038+ * it under the terms of the GNU General Public License version 3 as
2039+ * published by the Free Software Foundation.
2040+ *
2041+ * Ubuntu Clock App is distributed in the hope that it will be useful,
2042+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2043+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2044+ * GNU General Public License for more details.
2045+ *
2046+ * You should have received a copy of the GNU General Public License
2047+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2048+ */
2049+
2050+import QtQuick 2.4
2051+import QtTest 1.0
2052+import Ubuntu.Components 1.2
2053+import "../../app/stopwatch"
2054+
2055+TestCase {
2056+ id: stopwatchUtilsTest
2057+ name: "StopwatchUtilsLibrary"
2058+
2059+ StopwatchUtils {
2060+ id: stopwatchUtils
2061+ }
2062+
2063+ /*
2064+ This test checks if the milliseconds is returned correctly in the format
2065+ mmm (string length 3)
2066+ */
2067+ function test_returnMillisecond() {
2068+ var result
2069+ result = stopwatchUtils.millisToString(400)
2070+ compare(result, "400", "Milliseconds not properly converted to the format required")
2071+ result = stopwatchUtils.millisToString(4)
2072+ compare(result, "004", "Milliseconds not properly converted to the format required")
2073+ }
2074+
2075+ /*
2076+ This test checks if the time (in milliseconds) to converted to hh:mm:ss
2077+ correctly.
2078+ */
2079+ function test_convertTimeInMillisecondsToString() {
2080+ var timeInMilliseconds = 1123000
2081+ var result = stopwatchUtils.millisToTimeString(timeInMilliseconds, false, true)
2082+ compare(result, "00:18:43", "Time not properly converted from milliseconds to hh:mm:ss")
2083+ }
2084+
2085+ /*
2086+ This test checks if the zero prefix is added correctly to ensure that a
2087+ string is always of the specified string length.
2088+ */
2089+ function test_zeroPrefixAddedCorrectly() {
2090+ var str = "32", result
2091+ result = stopwatchUtils.addZeroPrefix(str, 2)
2092+ compare(result, "32", "Zero prefix not added correctly")
2093+ result = stopwatchUtils.addZeroPrefix(str, 3)
2094+ compare(result, "032", "Zero prefix not added correctly")
2095+ result = stopwatchUtils.addZeroPrefix(str, 4)
2096+ compare(result, "0032", "Zero prefix not added correctly")
2097+ }
2098+
2099+ /*
2100+ This test checks if the lap time correctly shows or hides the hours
2101+ as requires and returns it as a string.
2102+ */
2103+ function test_lapTimeIncludesHoursCorrectly() {
2104+ var result
2105+ result = stopwatchUtils.lapTimeToString(1123000)
2106+ compare(result, "18:43", "Lap time shows hours despite it not being greater than 0")
2107+ result = stopwatchUtils.lapTimeToString(8323000)
2108+ compare(result, "02:18:43", "Lap time not showing hours despite it being greater than 0")
2109+ }
2110+}
2111
2112=== modified file 'tests/unit/tst_worldClock.qml'
2113--- tests/unit/tst_worldClock.qml 2015-08-12 16:57:29 +0000
2114+++ tests/unit/tst_worldClock.qml 2015-08-20 20:43:05 +0000
2115@@ -16,7 +16,7 @@
2116 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2117 */
2118
2119-import QtQuick 2.0
2120+import QtQuick 2.4
2121 import QtTest 1.0
2122 import Ubuntu.Test 1.0
2123 import Ubuntu.Components 1.2
2124
2125=== modified file 'ubuntu-clock-app.json'
2126--- ubuntu-clock-app.json 2015-05-27 16:03:23 +0000
2127+++ ubuntu-clock-app.json 2015-08-20 20:43:05 +0000
2128@@ -3,7 +3,8 @@
2129 "audio",
2130 "calendar",
2131 "networking",
2132- "location"
2133+ "location",
2134+ "keep-display-on"
2135 ],
2136 "policy_version": 1.3
2137-}
2138\ No newline at end of file
2139+}

Subscribers

People subscribed via source and target branches

to all changes: