diff --git a/Changelog b/Changelog
index 23cd512..395a850 100644
--- a/Changelog
+++ b/Changelog
@@ -1,7 +1,10 @@
0.3
- Landscape orientation enabled.
- Variable screen size now works.
-- Load the last timer value on program start.
+- Optionally load the last timer value on program start.
+- Use MusicPickerPage for selected alarm sound file.
+- Predefined timers were too wide.
+- Couldn't change predefined sec/min to 0.
0.2.1
- Timer didn't show on Sailfish OS 1.1.9.
diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml
index 3c5f17e..b01e5ab 100644
--- a/qml/cover/CoverPage.qml
+++ b/qml/cover/CoverPage.qml
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-15 Thomas Tanghus
+ Copyright (C) 2013-19 Thomas Tanghus
All rights reserved.
You may use this file under the terms of BSD license as follows:
@@ -46,7 +46,7 @@ CoverBackground {
truncationMode: TruncationMode.Fade;
horizontalAlignment: Text.AlignHCenter;
width: parent.width;
- font.pixelSize: Theme.fontSizeLarge;
+ font.pixelSize: Theme.fontSizeExtraLarge;
}
Label {
text: timeText;
diff --git a/qml/harbour-kitchentimer.qml b/qml/harbour-kitchentimer.qml
index 3114f6f..a132637 100644
--- a/qml/harbour-kitchentimer.qml
+++ b/qml/harbour-kitchentimer.qml
@@ -30,7 +30,6 @@
import QtQuick 2.0
import QtMultimedia 5.6
import Sailfish.Silica 1.0
-//import Sailfish.Media 1.0
import harbour.kitchentimer.insomniac 1.0
import "pages"
import "cover"
@@ -40,163 +39,188 @@ ApplicationWindow {
id: app;
- property string timeText: '00:01';
- property bool useDefaultSound: true;
- property bool loadLast: true;
- property bool loopSound: true;
- property string builtinSound: Qt.resolvedUrl('../sounds/harbour-kitchentimer.wav');
- property string selectedSound: builtinSound;
- property bool isBusy: false;
- // Close enough to assume screen is off.
+ property string timeText: "00:00"
+ property int timersAlignment: Dock.Left
+ property bool loadLast: true
+ property bool useDefaultSound: true
+ property bool loopSound: true
+ property string builtinSound: Qt.resolvedUrl("../sounds/harbour-kitchentimer.wav")
+ property string selectedSound
+ property bool isBusy: false
+ // Close enough to determine whether screen is on or off.
property bool viewable: cover.status === Cover.Active
|| cover.status === Cover.Activating
- || applicationActive;
- property bool isPlaying: alarm.playbackState === Audio.PlayingState;
- property bool isRunning: timer.running || insomniac.running;
- property alias seconds: timerPage.seconds;
- property alias minutes: timerPage.minutes;
- property int lastTimerMin: -1;
- property int lastTimerSec: -1;
- property int _lastTick: 0;
+ || applicationActive
+ property bool isPlaying: alarm.playbackState === Audio.PlayingState
+ property bool isRunning: timer.running || insomniac.running
+ property alias seconds: timerPage.seconds
+ property alias minutes: timerPage.minutes
+ property int lastTimerMin: -1
+ property int lastTimerSec: -1
+ property int _lastTick: 0
// Remaining time in seconds when screen blanks
- property int _remaining: 0;
+ property int _remaining: 0
- allowedOrientations: Orientation.Portrait | Orientation.Landscape; //defaultAllowedOrientations
+ allowedOrientations: Orientation.Portrait | Orientation.Landscape //defaultAllowedOrientations
onViewableChanged: {
if(!isRunning) {
- return;
+ return
}
if(viewable) {
- wakeUp();
+ wakeUp()
} else {
- snooze();
+ snooze()
}
-
}
Component.onCompleted: {
- load();
+ load()
+ }
+
+ Component.onDestruction: {
+ // Apparently this is never called
+ console.log("ApplicationWindow.onDestruction:")
+ saveSettings()
+ saveTimers()
}
initialPage: TimerPage {
- id: timerPage;
+ id: timerPage
}
cover: CoverPage {
- id: cover;
+ id: cover
}
BusyIndicator {
- id: busyIndicator;
- anchors.centerIn: parent;
- size: BusyIndicatorSize.Large;
+ id: busyIndicator
+ anchors.centerIn: parent
+ size: BusyIndicatorSize.Large
}
ListModel {
- id: timersModel;
+ id: timersModel
}
Audio {
- id: alarm;
- loops: loopSound ? Audio.Infinite : 1;
- source: useDefaultSound ? builtinSound : Qt.resolvedUrl(selectedSound);
- audioRole: Audio.AlarmRole;
+ id: alarm
+ loops: loopSound ? Audio.Infinite : 1
+ source: useDefaultSound ? builtinSound : Qt.resolvedUrl(selectedSound)
+ audioRole: Audio.AlarmRole
onError: {
console.log("Audio error:", errorString, selectedSound)
}
}
Timer {
- id: timer;
- interval: 1000;
+ id: timer
+ interval: 1000
running: false; repeat: true;
onTriggered: {
- var now = Math.round(Date.now()/1000);
- seconds -= now - _lastTick;
- _lastTick = now;
- //console.log('seconds', seconds);
+ var now = Math.round(Date.now()/1000)
+ seconds -= now - _lastTick
+ _lastTick = now
if(minutes === 0 && seconds === 0) {
- reset();
- playAlarm();
+ reset()
+ playAlarm()
}
}
}
Timer {
- id: wakeupTimer;
- interval: 1000;
+ id: wakeupTimer
+ interval: 1000
running: false; repeat: false;
onTriggered: {
- alarm.play();
- app.activate();
+ alarm.play()
+ app.activate()
pageStack.pop(timerPage)
}
}
Insomniac {
- id: insomniac;
- repeat: false;
- timerWindow: 10;
+ id: insomniac
+ repeat: false
+ timerWindow: 10
onTimeout: {
- wakeUp();
+ wakeUp()
}
onError: {
- console.warn('Error in wake-up timer');
+ console.warn("Error in wake-up timer")
}
}
Storage {
- id: storage;
- dbName: StandardPaths.data;
+ id: storage
+ dbName: StandardPaths.data
}
Connections {
- target: cover;
- onMute: mute();
- onPause: pause();
- onReset: reset();
- onStart: start();
+ target: cover
+ onMute: mute()
+ onPause: pause()
+ onReset: reset()
+ onStart: start()
+ }
+
+ function saveSettings() {
+ setBusy(true)
+
+ // The values are assigned in timerPage.onAccept
+ settings.setValue("timersAlignment", timersAlignment)
+ settings.setValue("loopSound", loopSound)
+ settings.setValue("loadLast", loadLast)
+ settings.setValue("useDefaultSound", useDefaultSound)
+
+ if(!useDefaultSound) {
+ settings.setValue("selectedSound", selectedSound)
+ }
+ setBusy(false)
}
- function save() {
- setBusy(true);
- var timers = [];
+ function saveTimers() {
+ setBusy(true)
+ var timers = []
for (var i = 0; i < timersModel.count; ++i) {
- var timer = timersModel.get(i);
- timers.push({name:timer.name, minutes: timer.minutes, seconds:timer.seconds});
+ var timer = timersModel.get(i)
+ timers.push({name:timer.name, minutes: timer.minutes, seconds:timer.seconds})
}
- storage.saveTimers(timers);
- setBusy(false);
+ storage.saveTimers(timers)
+ setBusy(false)
}
function load() {
- setBusy(true);
-
- loopSound = settings.value('loopSound', true);
- loadLast = settings.value('loadLast', true)
- useDefaultSound = settings.value('useDefaultSound', true);
- console.log("Default sound?", useDefaultSound)
- selectedSound = useDefaultSound ? builtinSound : settings.value('selectedSound', builtinSound);
- console.log("Selected sound:", selectedSound)
+ setBusy(true)
+
+ loopSound = settings.value("loopSound", true)
+ timersAlignment = settings.value("timersAlignment", Dock.Left)
+ loadLast = settings.value("loadLast", true)
+ useDefaultSound = settings.value("useDefaultSound", true)
+ selectedSound = settings.value("selectedSound", "")
if(loadLast) {
- minutes = lastTimerMin = settings.value("lastTimerMin", -1);
- seconds = lastTimerSec = settings.value("lastTimerSec", -1);
+ minutes = lastTimerMin = settings.value("lastTimerMin", -1)
+ seconds = lastTimerSec = settings.value("lastTimerSec", -1)
}
+ loadTimers()
+
// For some odd reason the app isn't set to active on load..?
//app.activate();
- applicationActive = true;
- showTime();
+ applicationActive = true
+ showTime()
+ setBusy(false)
+ }
- var timers = storage.getTimers();
+ function loadTimers() {
+ var timers = storage.getTimers()
if(timers === false) {
- console.warn('Default timers could not be loaded');
- setBusy(false);
+ console.warn("Default timers could not be loaded")
+ setBusy(false)
return
}
@@ -207,110 +231,123 @@ ApplicationWindow {
minutes: timers[i].minutes,
seconds: timers[i].seconds
}
- );
+ )
}
- setBusy(false);
}
- function reload() {
- timersModel.clear();
- load();
+ function reloadTimers() {
+ timersModel.clear()
+ loadTimers()
}
function setBusy(state) {
- isBusy = state;
- busyIndicator.running = state;
+ isBusy = state
+ busyIndicator.running = state
}
function showTime() {
if(!viewable) {
- return;
+ return
}
- timeText = Qt.formatTime(new Date(0, 0, 0, 0, minutes, seconds), 'mm:ss');
+ timeText = Qt.formatTime(new Date(0, 0, 0, 0, minutes, seconds), 'mm:ss')
}
function setTime(mins, secs) {
- minutes = mins;
- seconds = secs;
+ minutes = mins
+ seconds = secs
}
function mute() {
if(alarm.playbackState === Audio.PlayingState) {
- alarm.stop();
+ alarm.stop()
}
}
function pause() {
if(timer.running) {
- timer.stop();
+ timer.stop()
}
}
function reset() {
if(timer.running) {
- timer.stop();
+ timer.stop()
}
if(insomniac.running) {
- insomniac.stop();
+ insomniac.stop()
}
- seconds = minutes = _remaining = _lastTick = 0;
+ seconds = minutes = _remaining = _lastTick = 0
}
function start() {
if(!timer.running) {
- _lastTick = Math.round(Date.now()/1000);
- lastTimerMin = minutes;
- lastTimerSec = seconds;
- settings.setValue("lastTimerMin", lastTimerMin);
- settings.setValue("lastTimerSec", lastTimerSec);
- timer.start();
+ _lastTick = Math.round(Date.now()/1000)
+ lastTimerMin = minutes
+ lastTimerSec = seconds
+ settings.setValue("lastTimerMin", lastTimerMin)
+ settings.setValue("lastTimerSec", lastTimerSec)
+ timer.start()
}
}
function snooze() {
- timer.stop();
- _remaining = seconds + (minutes * 60);
- _lastTick = Math.round(Date.now()/1000);
+ timer.stop()
+ _remaining = seconds + (minutes * 60)
+ _lastTick = Math.round(Date.now()/1000)
// Subtract 10 seconds for timer window
- insomniac.interval =_remaining - 10;
- insomniac.start();
+ insomniac.interval =_remaining - 10
+ insomniac.start()
}
function wakeUp() {
if(insomniac.running) {
- insomniac.stop();
+ insomniac.stop()
}
- var now = Math.round(Date.now()/1000);
- var passed = now - _lastTick;
- _lastTick = now;
+ var now = Math.round(Date.now()/1000)
+ var passed = now - _lastTick
+ _lastTick = now
if(passed >= _remaining) {
- console.warn('Time has passed!', passed - _remaining, 'seconds');
- reset();
- playAlarm();
+ console.warn('Time has passed!', passed - _remaining, 'seconds')
+ reset()
+ playAlarm()
} else {
- timer.start();
- _remaining = _remaining - passed;
+ timer.start()
+ _remaining = _remaining - passed
if(_remaining > 60) {
- minutes = Math.floor(_remaining/60);
- seconds = Math.round(_remaining - (minutes*60));
+ minutes = Math.floor(_remaining/60)
+ seconds = Math.round(_remaining - (minutes*60))
} else {
- minutes = 0;
- seconds = _remaining;
+ minutes = 0
+ seconds = _remaining
}
}
}
function playAlarm() {
- display.unBlank();
+ display.unBlank()
if(display.isLocked()) {
- display.unLock();
+ display.unLock()
}
// Apparently Lipstick(?) needs some time before you can activate the app.
- wakeupTimer.start();
+ wakeupTimer.start()
}
-}
+ function formatTime(text) {
+ var t = parseInt(text), newText
+ // If the delegate hasn't instantiated yet - I guess...
+ if(t === NaN) {
+ return "00"
+ }
+
+ // I'd like to do this in a READABLE one-liner
+ // Make sure that time is not more than 59 mins. and 59 secs
+ newText = t < 60 ? String(t) : "59"
+ // Format time '0' => '00', '9' => '09' etc.
+ newText = t >= 10 ? String(t) : "0" + String(t)
+ return newText
+ }
+}
diff --git a/qml/pages/AboutPage.qml b/qml/pages/AboutPage.qml
index ef094fe..af158c5 100644
--- a/qml/pages/AboutPage.qml
+++ b/qml/pages/AboutPage.qml
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-15 Thomas Tanghus
+ Copyright (C) 2013-19 Thomas Tanghus
All rights reserved.
You may use this file under the terms of BSD license as follows:
@@ -46,6 +46,7 @@ Page {
y: Theme.paddingLarge
anchors.top: header.bottom;
anchors.horizontalCenter: parent.horizontalCenter
+ width: 128; height: 128
//opacity: 0.4
source: "image://theme/harbour-kitchentimer"
}
diff --git a/qml/pages/SettingsDialog.qml b/qml/pages/SettingsDialog.qml
index f3a44ca..3647f7e 100644
--- a/qml/pages/SettingsDialog.qml
+++ b/qml/pages/SettingsDialog.qml
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2015 Thomas Tanghus
+ Copyright (C) 2015-2019 Thomas Tanghus
All rights reserved.
You may use this file under the terms of BSD license as follows:
@@ -32,6 +32,7 @@ import QtMultimedia 5.6
import Sailfish.Silica 1.0
import Sailfish.Pickers 1.0
import Sailfish.Media 1.0
+//import "../components"
Dialog {
id: settingsDialog;
@@ -42,6 +43,8 @@ Dialog {
property bool tmpUseDefaultSound: useDefaultSound;
property bool tmpLoopSound: loopSound;
property bool tmpLoadLast: loadLast;
+ property int tmpTimersAlignment: timersAlignment
+ property alias timersAlignmentText: alignmentCombo.value
//canAccept: useDefaultSound || tmpSelectedSound !== selectedSound;
@@ -54,83 +57,125 @@ Dialog {
DialogHeader {
id: header;
dialog: settingsDialog;
- title: qsTr('Settings');
+ title: qsTr("Settings");
}
-
+
Column {
id: column;
-
+
y: header.height + Theme.paddingMedium;
//height: parent.height - (header.height + Theme.paddingMedium);
anchors.leftMargin: Theme.paddingLarge;
anchors.rightMargin: Theme.paddingLarge;
width: settingsDialog.width;
spacing: Theme.horizontalPageMargin;
-
+
TextSwitch {
id: doLoadLast;
checked: loadLast;
x: Theme.paddingLarge;
- text: qsTr('Load last timer');
- description: qsTr('Reload the last timer when starting the app');
+ text: qsTr("Load last timer");
+ description: qsTr("Reload the last timer when starting the app");
onCheckedChanged: {
- console.log('LoadLast', checked)
+ //console.log("LoadLast", checked)
tmpLoadLast = checked;
}
}
-
+
+ ComboBox {
+ id: alignmentCombo
+ label: qsTr("Timers menu alignment")
+ description: qsTr("Select to which side of the screen the predefined timers menu should be placed")
+ onCurrentIndexChanged: {
+ var alignmentObject = alignmentModel.get(currentIndex)
+ value = alignmentObject.align
+ tmpTimersAlignment = alignmentObject.value
+ timersAlignmentText = alignmentObject.align
+ }
+
+ Component.onCompleted: {
+ currentIndex = getIndex(timersAlignment)
+ value = alignmentModel.get(currentIndex).align
+ }
+
+ menu: ContextMenu {
+ Repeater {
+ model: alignmentModel
+ delegate: MenuItem {
+ Label {
+ text: model.align
+ }
+ }
+ }
+ ListModel {
+ id: alignmentModel
+ ListElement { align: qsTr("Left"); value: Dock.Left }
+ ListElement { align: qsTr("Right"); value: Dock.Right }
+ }
+ }
+
+ function getIndex(value) {
+ for(var i = 0; i < alignmentModel.count; i++) {
+ if(value === alignmentModel.get(i).value) {
+ console.log("Got it:", value)
+ return i
+ }
+ }
+ }
+ }
+
Label {
text: qsTr("Alarm sound")
x: Theme.paddingLarge;
color: Theme.highlightColor
- font.family: Theme.fontFamilyHeading }
+ font.family: Theme.fontFamilyHeading
+ }
TextSwitch {
id: doLoop;
checked: loopSound;
x: Theme.paddingLarge;
- text: qsTr('Loop alarm sound');
- description: qsTr('Repeat alarm sound until you stop it');
+ text: qsTr("Loop alarm sound");
+ description: qsTr("Repeat alarm sound until you stop it");
onCheckedChanged: {
- console.log('Loop', checked)
+ console.log("Loop", checked)
tmpLoopSound = checked;
}
}
-
+
TextSwitch {
id: soundSelector;
checked: useDefaultSound;
x: Theme.paddingLarge;
- text: qsTr('Default sound');
- description: qsTr('Use the alarm sound provided by the app');
+ text: qsTr("Default sound");
+ description: qsTr("Use the alarm sound provided by the app");
onCheckedChanged: {
- console.log('useDefaultSound', checked);
+ console.log("useDefaultSound", checked);
tmpUseDefaultSound = checked;
if(checked) {
sound.source = builtinSound;
//tmpSelectedSound = builtinSound;
- console.log('Using builtinSound', builtinSound);
+ console.log("Using builtinSound", builtinSound);
}
}
}
-
+
/*TextSwitch {
id: doVibrate;
checked: vibrate;
x: Theme.paddingLarge;
- text: qsTr('Vibrate');
- description: 'Since QtFeedback
is not yet allowed, this does nothing.';
+ text: qsTr("Vibrate");
+ description: "Since QtFeedback
is not yet allowed, this does nothing.";
onCheckedChanged: {
- console.log('Vibrate', checked)
+ console.log("Vibrate", checked)
vibrate = checked;
}
}*/
-
+
ValueButton {
enabled: !tmpUseDefaultSound;
- label: qsTr('Select music file')
+ label: qsTr("Select music file")
value: baseName(tmpSelectedSound)
- //enabled: !soundSelector.checked
onClicked: {
pageStack.push(musicPickerPage);
}
@@ -164,44 +209,38 @@ Dialog {
}
onAccepted: {
- loopSound = tmpLoopSound;
- settings.setValue('loopSound', loopSound);
+ timersAlignment = tmpTimersAlignment
+ loopSound = tmpLoopSound
loadLast = tmpLoadLast
- settings.setValue('loadLast', loadLast);
-
- useDefaultSound = tmpUseDefaultSound;
- settings.setValue('useDefaultSound', useDefaultSound);
-
- if(!useDefaultSound) {
- selectedSound = tmpSelectedSound;
- console.log("Saving not default sound", selectedSound)
- settings.setValue('selectedSound', selectedSound);
- }
+ useDefaultSound = tmpUseDefaultSound
+ selectedSound = tmpSelectedSound
+
+ // The settings should be saved in ApplicationWindow.onDestruction,
+ // but that isn't called when closing an app
+ saveSettings()
}
-
+
Component {
id: musicPickerPage
MusicPickerPage {
onSelectedContentPropertiesChanged: {
tmpSelectedSound = selectedContentProperties.filePath
- sound.source = tmpSelectedSound;
- console.log("Selected:", tmpSelectedSound);
+ sound.source = tmpSelectedSound
}
}
}
Audio {
- id: sound;
- loops: tmpLoopSound ? Audio.Infinite : 1;
- source: selectedSound;
- audioRole: Audio.AlarmRole;
+ id: sound
+ loops: tmpLoopSound ? Audio.Infinite : 1
+ source: selectedSound
+ audioRole: Audio.AlarmRole
onError: {
console.log("Audio error:", errorString, selectedSound)
}
}
function baseName(path) {
- return path.split(/[\\/]/).pop();
+ return path.split(/[\\/]/).pop()
}
}
-
diff --git a/qml/pages/TimerPage.qml b/qml/pages/TimerPage.qml
index 0b36435..db86750 100644
--- a/qml/pages/TimerPage.qml
+++ b/qml/pages/TimerPage.qml
@@ -35,85 +35,72 @@ Page {
id: timerPage;
allowedOrientations: Orientation.All;
- property alias seconds: kitchenTimer.seconds;
- property alias minutes: kitchenTimer.minutes;
- property Item contextMenu;
+ property alias seconds: kitchenTimer.seconds
+ property alias minutes: kitchenTimer.minutes
+ property Item contextMenu
Component.onCompleted: {
- showTime();
+ showTime()
}
onSecondsChanged: {
- showTime();
+ showTime()
}
onMinutesChanged: {
- showTime();
+ showTime()
}
SilicaFlickable {
- anchors.fill: parent;
-
- //onWidthChanged: {
- // console.log(orientation === Orientation.Portrait ? "Portrait" : "Landscape")
- //}
+ anchors.fill: parent
PullDownMenu {
MenuItem {
- text: qsTr('About');
+ text: qsTr("About")
onClicked: {
- pageStack.push(Qt.resolvedUrl('AboutPage.qml'));
+ pageStack.push(Qt.resolvedUrl("AboutPage.qml"))
}
}
MenuItem {
- text: qsTr('Edit default timers');
- onClicked: pageStack.push(Qt.resolvedUrl('TimersDialog.qml'));
+ text: qsTr("Edit default timers")
+ onClicked: pageStack.push(Qt.resolvedUrl("TimersDialog.qml"))
}
MenuItem {
- text: qsTr('Settings');
- onClicked: pageStack.push(Qt.resolvedUrl('SettingsDialog.qml'));
+ text: qsTr("Settings")
+ onClicked: pageStack.push(Qt.resolvedUrl("SettingsDialog.qml"))
}
MenuItem {
- text: qsTr('Last timer:')
- + ' ' + (lastTimerMin >= 10 ? lastTimerMin : '0' + String(lastTimerMin)) + ':'
- + (lastTimerSec >= 10 ? lastTimerSec : '0' + String(lastTimerSec));
+ text: qsTr("Last timer:")
+ + " " + (lastTimerMin >= 10 ? lastTimerMin : "0" + String(lastTimerMin)) + ":"
+ + (lastTimerSec >= 10 ? lastTimerSec : "0" + String(lastTimerSec))
onClicked: {
- setTime(lastTimerMin, lastTimerSec);
+ setTime(lastTimerMin, lastTimerSec)
}
- visible: lastTimerMin !== -1 && lastTimerSec !== -1;
+ visible: lastTimerMin !== -1 && lastTimerSec !== -1
}
}
PushUpMenu {
- visible: timersModel.count > 0;
- Repeater {
- model: timersModel;
- delegate: MenuItem {
- text: model.name + ' '
- + (model.minutes>= 10 ? model.minutes : '0' + String(model.minutes))
- + ':'
- + (model.seconds >= 10 ? model.seconds : '0' + String(model.seconds));
- onClicked: {
- setTime(model.minutes, model.seconds);
- console.log('Selected timer', model.name);
- }
- }
+ visible: !drawer.open
+ MenuItem {
+ text: qsTr("Timers")
+ onClicked: drawer.open = true
}
}
// Tell SilicaFlickable the height of its content.
- contentHeight: column.height;
+ contentHeight: column.height
Column {
id: column;
- width: Screen.width - (Theme.paddingLarge * 2);
- spacing: Theme.paddingLarge;
- anchors.centerIn: parent;
+ width: Screen.width - (Theme.paddingLarge * 2)
+ spacing: Theme.paddingLarge
+ anchors.centerIn: parent
PageHeader {
- id: header;
- title: qsTr('Kitchen Timer');
- visible: timerPage.isPortrait ? true : false;
+ id: header
+ title: qsTr("Kitchen Timer")
+ visible: timerPage.isPortrait ? true : false
}
// Dummy element to create some top spacing when in Landscape and to center
@@ -121,22 +108,28 @@ Page {
Item {
height: header.visible ?
(Screen.height/2)-(kitchenTimer.height/2)-header.height-(Theme.paddingLarge*2) :
- Theme.paddingLarge;
- width: parent.width;
+ Theme.paddingLarge
+ width: parent.width
}
Item {
- width: column.width - (Theme.paddingLarge * 2);
- height : width;
- anchors.horizontalCenter: parent.horizontalCenter;
+ width: column.width - (Theme.paddingLarge * 2)
+ height: width
+ anchors.horizontalCenter: parent.horizontalCenter
KitchenTimer {
- id: kitchenTimer;
- anchors.centerIn: parent;
+ id: kitchenTimer
+ anchors.centerIn: parent
}
BackgroundItem {
id: timerButton;
property alias text: timerButtonLabel.text
+
+ drag.target: drawer
+ drag.axis: Drag.XAxis
+ drag.minimumX: 10
+ drag.maximumX: timerPage.width // - rect.width
+
anchors.centerIn: kitchenTimer;
width: timerButtonLabel.width + (Theme.paddingLarge*2)
height: timerButtonLabel.height
@@ -169,14 +162,21 @@ Page {
}
}
+ onPositionChanged: {
+ console.log("Dragging?", x, y)
+ }
+
onPressedChanged: {
- if (pressed) {
+ console.log("Press changed", x, y)
+ /*
+ if(pressed) {
pressTimer.start()
- }
+ }*/
}
+
onCanceled: {
- timerButton.DragFilter.end()
- pressTimer.stop()
+ /*timerButton.DragFilter.end()
+ pressTimer.stop()*/
}
onClicked: {
@@ -188,7 +188,9 @@ Page {
start();
}
}
+
onPressAndHold: {
+ console.log("pressAndHold")
setMenuModel();
if((minutes === 0 && seconds === 0) & !isPlaying && !isRunning) {
return;
@@ -204,7 +206,7 @@ Page {
}
ListModel {
- id: menuModel;
+ id: menuModel
}
Timer {
@@ -213,18 +215,84 @@ Page {
}
Component {
- id: contextMenuComponent;
+ id: contextMenuComponent
ContextMenu {
+ container: timerButton
Repeater {
- id: menuRepeater;
- model: menuModel;
+ id: menuRepeater
+ model: menuModel
delegate: MenuItem {
- text: model.name;
- onClicked: {
- //console.log('Action:', model.action);
- runMenuAction(model.action);
- }
+ text: model.name
+ onClicked: runMenuAction(model.action)
+ }
+ }
+ }
+ }
+ } // end Flickable
+
+ // Close drawer when tapped outside of it
+ MouseArea {
+ visible: drawer.open
+ anchors.fill: parent
+ onClicked: drawer.open = false
+ }
+
+ Drawer {
+ id: drawer
+
+ open: false
+ dock: timersAlignment
+
+ anchors.fill: parent
+ hideOnMinimize: true
+ Drag.active: timerButton.drag.active
+ //Drag.hotSpot.x: 10
+ //Drag.hotSpot.y: 10
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity)
+ SilicaListView {
+ id: timersList
+ y: header.height
+ width: parent.width
+ height: parent.height - header.height
+ contentHeight: timersModel.count * Theme.itemSizeLarge
+
+ VerticalScrollDecorator {
+ }
+
+ model: timersModel
+
+ delegate: ListItem {
+ width: parent.width - Theme.horizontalPageMargin
+ Label {
+ id: timerNameLabel
+ truncationMode: TruncationMode.Fade
+ x: Theme.horizontalPageMargin
+ font.pixelSize: Theme.fontSizeSmall
+ text: model.name
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignLeft
+ width: parent.width/2
+ //color: parent.highlighted ? Theme.highlightColor : Theme.primaryColor
+ color: Theme.primaryColor
+ }
+
+ Label {
+ anchors.left: timerNameLabel.right
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: Theme.fontSizeSmall
+ horizontalAlignment: Text.AlignRight
+ text:formatTime(model.minutes) + ":" + formatTime(model.seconds)
+ color: Theme.primaryColor
+ }
+
+ onClicked: {
+ drawer.open = false
+ setTime(model.minutes, model.seconds)
}
}
}
@@ -233,43 +301,40 @@ Page {
function runMenuAction(action) {
switch(action) {
- case 'start':
- start();
- break;
- case 'reset':
- reset();
- break;
- case 'mute':
- mute();
- break;
- case 'pause':
- pause();
- break;
+ case "start":
+ start()
+ break
+ case "reset":
+ reset()
+ break
+ case "mute":
+ mute()
+ break
+ case "pause":
+ pause()
+ break
}
}
function setMenuModel() {
- menuModel.clear();
+ menuModel.clear()
var menuActions = {
- start: {name:qsTr('Start'), action:'start'},
- pause: {name:qsTr('Pause'), action:'pause'},
- reset: {name:qsTr('Reset'), action:'reset'},
- mute: {name:qsTr('Mute'), action:'mute'}
+ start: {name:qsTr("Start"), action:"start"},
+ pause: {name:qsTr("Pause"), action:"pause"},
+ reset: {name:qsTr("Reset"), action:"reset"},
+ mute: {name:qsTr("Mute"), action:"mute"}
}
if(isRunning) {
- menuModel.append(menuActions.pause);
- menuModel.append(menuActions.reset);
+ menuModel.append(menuActions.pause)
+ menuModel.append(menuActions.reset)
} else if(!isRunning && (minutes > 0 || seconds > 0)) {
- menuModel.append(menuActions.start);
- menuModel.append(menuActions.reset);
+ menuModel.append(menuActions.start)
+ menuModel.append(menuActions.reset)
} else if(minutes > 0 || seconds > 0) {
- menuModel.append(menuActions.reset);
+ menuModel.append(menuActions.reset)
} else if(alarm.playing) {
- menuModel.append(menuActions.mute);
+ menuModel.append(menuActions.mute)
}
}
-
}
-
-
diff --git a/qml/pages/TimersDialog.qml b/qml/pages/TimersDialog.qml
index e0507c9..e6d133a 100644
--- a/qml/pages/TimersDialog.qml
+++ b/qml/pages/TimersDialog.qml
@@ -34,24 +34,20 @@ import "../components"
Dialog {
id: timersDialog;
- allowedOrientations: Orientation.Portrait | Orientation.Landscape;
+ allowedOrientations: Orientation.Portrait | Orientation.Landscape
DialogHeader {
- id: header;
+ id: header
dialog: timersDialog
title: qsTr("Timers")
}
SilicaListView {
- id: timersList;
+ id: timersList
// TODO: Hide when list is outta sight
header: SectionHeader {
- //visible:
text: qsTr("Max value is '59:59'")
- onYChanged: {
- console.log("onYChanged:", y)
- }
}
footer: SectionHeader {
@@ -62,70 +58,70 @@ Dialog {
PushUpMenu {
id: menu
MenuItem {
- text: qsTr('Add timer');
+ text: qsTr("Add timer")
onClicked: {
console.log("Adding timer")
timersModel.append({
- name: 'New timer',
+ name: qsTr("New timer"),
minutes: 0,
seconds: 0
- });
- timersList.positionViewAtEnd();
+ })
+ timersList.positionViewAtEnd()
}
}
}
- model: timersModel;
+ model: timersModel
anchors {
horizontalCenter: header.horizontalCenter
- leftMargin: Theme.paddingLarge;
- rightMargin: Theme.paddingLarge;
+ leftMargin: Theme.paddingLarge
+ rightMargin: Theme.paddingLarge
}
- width: Screen.width;
- y: header.height + Theme.paddingMedium;
- contentHeight: timersModel.count * Theme.itemSizeMedium;
- height: parent.height - (header.height + Theme.paddingMedium);
+ width: Screen.width
+ y: header.height + Theme.paddingMedium
+ contentHeight: timersModel.count * Theme.itemSizeMedium
+ height: parent.height - (header.height + Theme.paddingMedium)
delegate: ListItem {
- id: timerItem;
- contentHeight: Theme.itemSizeSmall;
+ id: timerItem
+ contentHeight: Theme.itemSizeSmall
ListView.onRemove: animateRemoval(timerItem)
function remove() {
- remorseAction(qsTr('Deleting'), function() {
- timersList.model.remove(index);
+ remorseAction(qsTr("Deleting"), function() {
+ timersList.model.remove(index)
});
}
Item {
TextField {
- id: name;
- placeholderText: qsTr('Timer name');
- text: model.name;
- width: font.pixelSize * 8;
+ id: name
+ placeholderText: qsTr("Timer name")
+ text: model.name
+ width: font.pixelSize * 8
RegExpValidator { regExp: /(\w{1,10}\b)/g }
EnterKey.enabled: text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: minutes.focus = true
onFocusChanged: {
if(text.length > 0) {
- timersModel.setProperty(index, 'name', text);
+ timersModel.setProperty(index, "name", text)
}
}
}
TimeField {
id: minutes
- anchors.left: name.right;
+ anchors.left: name.right
timeType: "minutes"
- text: model.minutes >= 10 ? model.minutes : '0' + String(model.minutes);
- placeholderText: qsTr('Minutes');
+ text: model.minutes >= 10 ? model.minutes : '0' + String(model.minutes)
+ placeholderText: qsTr("Minutes")
errorHighlight: !validateTime(index, text, "minutes")
EnterKey.enabled: validateTime(index, text, "minutes")
EnterKey.onClicked: seconds.focus = true
onFocusChanged: {
if(validateTime(index, text, timeType)) {
- timersModel.setProperty(index, timeType, formatTime(text));
+ timersModel.setProperty(index, timeType, formatTime(text))
} else {
// Grab the value from the model
text = formatTime(timersModel.get(index)[timeType])
@@ -134,24 +130,24 @@ Dialog {
}
Label {
- id: separator;
- anchors.left: minutes.right;
- text: ':';
- color: minutes.color;
+ id: separator
+ anchors.left: minutes.right
+ text: ':'
+ color: minutes.color
}
TimeField {
id: seconds
- anchors.left: separator.right;
+ anchors.left: separator.right
timeType: "seconds"
- text: model.seconds >= 10 ? String(model.seconds) : '0' + String(model.seconds);
- placeholderText: qsTr('Seconds');
+ text: model.seconds >= 10 ? String(model.seconds) : '0' + String(model.seconds)
+ placeholderText: qsTr("Seconds")
errorHighlight: !validateTime(index, text, timeType)
EnterKey.enabled: validateTime(index, text, timeType)
EnterKey.onClicked: minutes.focus = true
onFocusChanged: {
if(validateTime(index, text, timeType)) {
- timersModel.setProperty(index, timeType, formatTime(text));
+ timersModel.setProperty(index, timeType, formatTime(text))
} else {
// Grab the value from the model
text = formatTime(timersModel.get(index)[timeType])
@@ -160,41 +156,24 @@ Dialog {
}
IconButton {
- anchors.left: seconds.right;
- icon.source: 'image://theme/icon-m-delete';
- onClicked: remove();
+ anchors.left: seconds.right
+ icon.source: "image://theme/icon-m-delete"
+ onClicked: remove()
}
}
}
VerticalScrollDecorator {
- flickable: timersList;
+ flickable: timersList
}
}
- onDone: {
- result === DialogResult.Accepted ? save() : reload();
- }
-
- function formatTime(text) {
- var t = parseInt(text), newText
-
- // If the delegate hasn't instantiated yet
- if(t === NaN) {
- return "00"
- }
-
- // I'd like to do this in a READABLE one-liner
- // Make sure that time is not more than 59 mins. and 59 secs
- newText = t < 60 ? String(t) : "59"
- // Format time '0' => '00', '9' => '09' etc.
- newText = t >= 10 ? String(t) : "0" + String(t);
- return newText
- }
+ onAccepted: saveTimers()
+ onRejected: reloadTimers()
/*
- * idx: int: Model index
- * timeText: String: The actual text in the TextField
- * minsec: String: Whether it's a "minutes" or "seconds" field
+ * in idx: Model index
+ * string timeText: The actual text in the TextField
+ * string minsec: Whether it's a "minutes" or "seconds" field
*/
function validateTime(idx, timeText, minsec) {
var minutes, seconds, item = timersModel.get(idx)
diff --git a/src/harbour-kitchentimer.cpp b/src/harbour-kitchentimer.cpp
index bf40295..fff7424 100644
--- a/src/harbour-kitchentimer.cpp
+++ b/src/harbour-kitchentimer.cpp
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include "qmlsettings.h"
#include "display.h"
@@ -58,6 +59,7 @@ int main(int argc, char *argv[])
// To display the view, call "show()" (will show fullscreen on device).
//return SailfishApp::main(argc, argv);
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));
//QGuiApplication* app = SailfishApp::application(argc, argv);
QScopedPointer app(SailfishApp::application(argc, argv));