# Generate buttons
generate 246 200 "button-journey-add button-journey-start button-journey-finish button-list button-stats"
+# Generate cover action icons
+generate 32 32 "icon-cover-journey-finish icon-cover-journey-start"
+
qml/components/InfoRow.qml \
qml/pages/JourneyEdit.qml \
qml/pages/JourneyInfo.qml \
- qml/components/BarButton.qml
+ qml/components/BarButton.qml \
+ qml/cover/ClockView.qml \
+ qml/cover/LargeItem.qml
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172 256x256
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="31.999998"
+ height="31.999998"
+ viewBox="0 0 31.999999 31.999999"
+ id="svg12804"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="icon-cover-journey-finish.svg">
+ <defs
+ id="defs12806" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#1f1f1f"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7.9195959"
+ inkscape:cx="-23.249276"
+ inkscape:cy="19.596642"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="px"
+ inkscape:window-width="3200"
+ inkscape:window-height="1773"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata12809">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-355.42857,-436.3622)">
+ <g
+ transform="translate(189.79905,-376.76244)"
+ id="g8251">
+ <rect
+ height="32"
+ width="32"
+ style="opacity:0;fill:#ffffff"
+ id="icon-cover-pause_3_-5-2-3"
+ x="165.62952"
+ y="813.12463" />
+ <path
+ sodipodi:nodetypes="cssccsscc"
+ inkscape:connector-curvature="0"
+ d="m 191.33889,841.84461 c 1.65,0 3,-1.35 3,-3 l 0,-19.439 c 0,-1.65 -1.35,-3 -3,-3 l -19.41875,0 c -1.65,0 -3,1.35 -3,3 l 0,19.438 c 0,1.65 1.35,3 3,3 z"
+ style="fill:#ffffff;stroke:none"
+ id="path8256-0-6" />
+ </g>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="31.999998"
+ height="31.999998"
+ viewBox="0 0 31.999999 31.999999"
+ id="svg8283"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="icon-cover-journey-start.svg">
+ <defs
+ id="defs8285" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#1f1f1f"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7.9195959"
+ inkscape:cx="5.0803359"
+ inkscape:cy="0.64592393"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="px"
+ inkscape:window-width="3200"
+ inkscape:window-height="1773"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata8288">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-109.71429,-419.21935)">
+ <g
+ id="icon-cover-play_2_-3"
+ transform="translate(109.71429,419.21935)">
+ <rect
+ height="32"
+ width="32"
+ style="opacity:0;fill:#ffffff"
+ id="icon-cover-play_3_-6"
+ x="0"
+ y="0" />
+ <path
+ id="path8234"
+ d="m 25.342,17.284 c 1.034,-0.706 1.034,-1.861 0,-2.568 L 9.095,3.617 C 8.061,2.911 7.215,3.357 7.215,4.609 l 0,22.781 c 0,1.252 0.846,1.699 1.88,0.993 L 25.342,17.284 Z"
+ style="fill:#ffffff"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+</svg>
--- /dev/null
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+
+Item {
+ id: root
+
+ property QtObject timerClock
+
+ // Size of the clock border decoration as a fraction of the radius
+ property real _faceRadiusBase: 84
+ property real _faceHourLength: 14.736 / _faceRadiusBase
+
+ Image {
+ id: clockFace
+
+ anchors.fill: parent
+ fillMode: Image.PreserveAspectFit
+ source: "image://theme/graphic-clock-face-3"
+ }
+
+ ShaderEffect {
+ id: timerVisualization
+
+ anchors.fill: clockFace
+
+ visible: stopwatch.update
+
+ onVisibleChanged: {
+ _updateTimerVisualization()
+ }
+
+ property int _seconds: stopwatch.seconds
+ on_SecondsChanged: _updateTimerVisualization()
+
+ property real outerRadius: 1
+ property real innerRadius: 1 - _faceHourLength
+ property real endAngle
+ property real loopRadius: outerRadius / 10
+ property real count
+
+ property color highlightColor: Theme.rgba(Theme.highlightColor, 0.75)
+
+ function _updateTimerVisualization() {
+ if (stopwatch.fast) {
+ count = _seconds
+ }
+ else {
+ count = Math.floor(_seconds / 60)
+ }
+
+ endAngle = 2 * Math.PI * count / 60
+ innerRadius = outerRadius - loopRadius * (parseInt(count / 60) + 1)
+ }
+
+ vertexShader: "
+ uniform highp mat4 qt_Matrix;
+ attribute highp vec4 qt_Vertex;
+ attribute highp vec2 qt_MultiTexCoord0;
+ varying highp vec2 coord;
+ void main() {
+ coord = qt_MultiTexCoord0;
+ gl_Position = qt_Matrix * qt_Vertex;
+ }"
+ fragmentShader: "
+ varying highp vec2 coord;
+ uniform lowp float qt_Opacity;
+ uniform lowp float outerRadius;
+ uniform lowp float innerRadius;
+ uniform lowp float endAngle;
+ uniform lowp float loopRadius;
+ uniform lowp vec4 highlightColor;
+ uniform lowp float count;
+
+ lowp float PI = 3.14159265358979323846264;
+
+ void main() {
+ highp vec2 vector = 2.0*(coord - vec2(0.5, 0.5));
+ lowp float radius = length(vector);
+ lowp float angle = atan(vector.y, vector.x) + PI/2.0;
+ angle += angle < 0.0 ? 2.0*PI : 0.0;
+
+ lowp float minRadius = outerRadius - ((count / 60.0) + 1.0) * loopRadius + (loopRadius * angle / (2.0 * PI));
+ lowp float maxRadius = outerRadius - ((mod(count, 60.0) / 60.0) + 1.0) * loopRadius + (loopRadius * angle / (2.0 * PI));
+
+ if (angle < 2.0 * PI * mod(count, 60.0) / 60.0) {
+ maxRadius += loopRadius;
+ }
+
+ if (radius >= minRadius && radius < maxRadius) {
+ if (mod(radius - minRadius, loopRadius) > 0.2 * loopRadius) {
+ gl_FragColor = highlightColor;
+ return;
+ }
+ }
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+ return;
+ }"
+ }
+}
import QtQuick 2.0
import Sailfish.Silica 1.0
+import harbour.pedalo.settings 1.0
CoverBackground {
- Label {
- id: label
- anchors.centerIn: parent
- text: qsTr("My Cover")
+ id: root
+ property bool update: status === Cover.Active && currentStatus.cycling
+
+ onUpdateChanged: {
+ stopwatch.updateseconds()
+ stopwatchtrigger.restart()
+ }
+
+ Item {
+ id: stopwatch
+ property int seconds: 0
+ property int fast: seconds < 60 * 10
+ property bool update: root.update
+
+ Timer {
+ id: stopwatchtrigger
+ interval: stopwatch.fast ? 200 : 5000
+ running: root.update
+ repeat: true
+ triggeredOnStart: true
+ onTriggered: {
+ stopwatch.updateseconds()
+ }
+ }
+
+ function updateseconds() {
+ stopwatch.seconds = (new Date().getTime() - currentStatus.startTime) / 1000
+ }
+ }
+
+ Item {
+ id: contents
+
+ width: Theme.coverSizeLarge.width
+ height: Theme.coverSizeLarge.height
+ property real xScale: root.width / contents.width
+
+ transform: Scale {
+ xScale: contents.xScale
+ yScale: root.height / contents.height
+ }
+
+ ClockView {
+ id: clockView
+
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ margins: Theme.paddingLarge
+ }
+ height: width
+ }
+
+ LargeItem {
+ id: stopwatchView
+
+ anchors {
+ top: clockView.bottom
+ topMargin: Theme.paddingMedium
+ leftMargin: Theme.paddingLarge
+ rightMargin: Theme.paddingLarge
+ }
+
+ textVisible: root.update
+
+ title: qsTr("Pedalo")
+
+ text: {
+ if (stopwatch.seconds < 60) {
+ return qsTr("%n seconds", "", stopwatch.seconds)
+ } else if (stopwatch.seconds < 60*60) {
+ return qsTr("%1 minutes").arg(Math.floor(stopwatch.seconds/60))
+ } else {
+ var minutes = Math.floor(stopwatch.seconds/60)
+ var hours = Math.floor(minutes/60)
+ minutes = minutes % 60
+ return qsTrId("%1h %2min").arg(hours).arg(minutes)
+ }
+ }
+ }
}
CoverActionList {
id: coverAction
CoverAction {
- iconSource: "image://theme/icon-cover-next"
- }
+ iconSource: currentStatus.cycling ? Settings.getImageUrl("icon-cover-journey-finish") : Settings.getImageUrl("icon-cover-journey-start")
+ onTriggered: {
+ if (currentStatus.cycling) {
+ app.activate()
+ app.showMainPage(PageStackAction.Immediate)
- CoverAction {
- iconSource: "image://theme/icon-cover-pause"
+ var dialog = pageStack.push(Qt.resolvedUrl("../pages/JourneyEdit.qml"), {title: "Finish journey", start: journeymodel.epochToDateTime(currentStatus.startTime), duration: currentStatus.getDuration()})
+
+ dialog.accepted.connect(function() {
+ currentStatus.cycling = false
+ })
+ }
+ else {
+ currentStatus.startJourney()
+ }
+ }
}
}
}
--- /dev/null
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+
+Column {
+ property alias title: titleLabel.text
+ property alias titleVisible: titleLabel.visible
+ property alias text: subLabel.text
+ property alias textVisible: subLabel.visible
+
+ anchors {
+ left: parent ? parent.left : undefined
+ right: parent ? parent.right : undefined
+ }
+
+ Label {
+ id: titleLabel
+
+ width: Math.min(parent.width, implicitWidth)
+ x: (parent.width - width) / 2
+
+ color: Theme.primaryColor
+ font.pixelSize: Theme.fontSizeLarge
+ truncationMode: TruncationMode.Fade
+ }
+
+ Label {
+ id: subLabel
+
+ width: Math.min(parent.width, implicitWidth)
+ x: (parent.width - width) / 2
+
+ color: Theme.highlightColor
+ font.pixelSize: Theme.fontSizeExtraSmall
+ truncationMode: TruncationMode.Fade
+ }
+}
ApplicationWindow
{
+ id: app
initialPage: Component { MainPage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: defaultAllowedOrientations
+
+ function showMainPage(operationType) {
+ var first = pageStack.currentPage
+ var temp = pageStack.previousPage(pageStack.currentPage)
+ while (temp) {
+ first = temp
+ temp = pageStack.previousPage(temp)
+ }
+
+ pageStack.pop(first, operationType)
+ }
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
+<context>
+ <name></name>
+ <message id="%1h %2min">
+ <source></source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
<context>
<name>About</name>
<message>
<context>
<name>CoverPage</name>
<message>
- <source>My Cover</source>
- <translation>Mein Cover</translation>
+ <source>Pedalo</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n seconds</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>%1 minutes</source>
+ <translation type="unfinished"></translation>
</message>
</context>
<context>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
+<context>
+ <name></name>
+ <message id="%1h %2min">
+ <source></source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
<context>
<name>About</name>
<message>
<context>
<name>CoverPage</name>
<message>
- <source>My Cover</source>
+ <source>Pedalo</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n seconds</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>%1 minutes</source>
<translation type="unfinished"></translation>
</message>
</context>