diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc
index 500749b6..fead8948 100644
--- a/nymea-app/resources.qrc
+++ b/nymea-app/resources.qrc
@@ -51,6 +51,8 @@
ui/components/FingerprintVisual.qml
ui/components/ListSectionHeader.qml
ui/components/ListFilterInput.qml
+ ui/components/Led.qml
+ ui/components/ProgressButton.qml
ui/customviews/GenericTypeLogView.qml
ui/customviews/CustomViewBase.qml
ui/customviews/WeatherView.qml
@@ -77,6 +79,7 @@
ui/devicepages/NotificationsDevicePage.qml
ui/devicepages/LightDevicePage.qml
ui/devicepages/FingerprintReaderDevicePage.qml
+ ui/devicepages/DeviceLogPage.qml
ui/devicelistpages/GenericDeviceListPage.qml
ui/devicelistpages/LightsDeviceListPage.qml
ui/devicelistpages/SensorsDeviceListPage.qml
@@ -136,7 +139,5 @@
ui/system/MqttBrokerSettingsPage.qml
ui/system/ServerConfigurationDialog.qml
ui/system/MqttPolicyPage.qml
- ui/devicepages/DeviceLogPage.qml
- ui/components/Led.qml
diff --git a/nymea-app/ui/components/ProgressButton.qml b/nymea-app/ui/components/ProgressButton.qml
new file mode 100644
index 00000000..529f6e4d
--- /dev/null
+++ b/nymea-app/ui/components/ProgressButton.qml
@@ -0,0 +1,122 @@
+import QtQuick 2.9
+import QtQuick.Layouts 1.3
+
+Item {
+ id: root
+
+ property string imageSource
+ property string longpressImageSource: imageSource
+ property bool repeat: false
+
+ property bool longpressEnabled: true
+
+ signal clicked();
+ signal longpressed();
+
+ MouseArea {
+ id: buttonDelegate
+ anchors.fill: parent
+
+ property bool longpressed: false
+
+ onPressed: {
+ canvas.inverted = false
+ buttonDelegate.longpressed = false
+ }
+ onReleased: {
+ if (!containsMouse) {
+ print("cancelled")
+ buttonDelegate.longpressed = false;
+ return;
+ }
+
+ if (buttonDelegate.longpressed) {
+ if (!repeat) {
+ root.longpressed();
+ }
+ } else {
+ root.clicked();
+ }
+ buttonDelegate.longpressed = false
+ }
+
+ NumberAnimation {
+ target: canvas
+ properties: "progress"
+ from: 0.0
+ to: 1.0
+ running: root.longpressEnabled && buttonDelegate.pressed
+ duration: 750
+ onRunningChanged: {
+ if (!running && canvas.progress == 1) {
+ buttonDelegate.longpressed = true;
+ if (root.repeat) {
+ root.longpressed();
+ start();
+ canvas.inverted = !canvas.inverted
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: -app.margins / 2
+ radius: width / 2
+ color: app.foregroundColor
+ opacity: buttonDelegate.pressed ? .08 : 0
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+ }
+
+ Canvas {
+ id: canvas
+ anchors.fill: parent
+ anchors.margins: -app.margins / 2
+
+ property real progress: 0
+ property bool inverted: false
+
+ readonly property int penWidth: 2
+ onProgressChanged: {
+ requestPaint()
+ }
+ Connections {
+ target: buttonDelegate
+ onPressedChanged: {
+ if (!buttonDelegate.pressed) {
+ canvas.progress = 0;
+ canvas.requestPaint()
+ }
+ }
+ }
+
+ onPaint: {
+ var ctx = getContext("2d");
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
+ ctx.lineWidth = canvas.penWidth
+ ctx.strokeStyle = app.accentColor
+
+ var start = -Math.PI / 2;
+ var stop = -Math.PI / 2;
+ if (inverted) {
+ start += canvas.progress * 2 * Math.PI
+ } else {
+ stop += canvas.progress * 2 * Math.PI
+ }
+
+ ctx.beginPath();
+ ctx.arc(canvas.width / 2, canvas.height / 2, ((canvas.width - canvas.penWidth) / 2), start, stop);
+ ctx.stroke();
+ }
+ }
+
+ ColorIcon {
+ anchors.fill: parent
+ name: buttonDelegate.longpressed ? root.longpressImageSource : root.imageSource
+ }
+ }
+}
+
diff --git a/nymea-app/ui/devicepages/MediaDevicePage.qml b/nymea-app/ui/devicepages/MediaDevicePage.qml
index e68a017c..8d0695a6 100644
--- a/nymea-app/ui/devicepages/MediaDevicePage.qml
+++ b/nymea-app/ui/devicepages/MediaDevicePage.qml
@@ -2,6 +2,7 @@ import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
import QtQuick.Layouts 1.1
+import QtGraphicalEffects 1.0
import Nymea 1.0
import "../components"
import "../customviews"
@@ -93,45 +94,56 @@ DevicePageBase {
Layout.fillWidth: true
Item { Layout.fillWidth: true }
- ItemDelegate {
+ ProgressButton {
Layout.preferredHeight: app.iconSize
Layout.preferredWidth: height
- leftPadding: 0; topPadding: 0; rightPadding: 0; bottomPadding: 0
- contentItem: ColorIcon {
- name: "../images/media-skip-backward.svg"
- }
+ imageSource: "../images/media-skip-backward.svg"
+ longpressImageSource: "../images/media-seek-backward.svg"
+ repeat: true
+
onClicked: {
root.executeAction("skipBack")
}
+ onLongpressed: {
+ root.executeAction("fastRewind")
+ }
}
Item { Layout.fillWidth: true }
- ItemDelegate {
+
+ ProgressButton {
Layout.preferredHeight: app.iconSize * 2
Layout.preferredWidth: height
- leftPadding: 0; topPadding: 0; rightPadding: 0; bottomPadding: 0
- contentItem: ColorIcon {
- name: root.playbackState.value === "Playing" ? "../images/media-playback-pause.svg" : "../images/media-playback-start.svg"
- }
+ imageSource: root.playbackState.value === "Playing" ? "../images/media-playback-pause.svg" : "../images/media-playback-start.svg"
+ longpressImageSource: "../images/media-playback-stop.svg"
+ longpressEnabled: root.playbackState.value !== "Stopped"
+
onClicked: {
- if (root,playbackState.value === "Playing") {
+ if (root.playbackState.value === "Playing") {
root.executeAction("pause")
} else {
root.executeAction("play")
}
}
+
+ onLongpressed: {
+ root.executeAction("stop")
+ }
}
+
Item { Layout.fillWidth: true }
- ItemDelegate {
+ ProgressButton {
Layout.preferredHeight: app.iconSize
Layout.preferredWidth: height
- leftPadding: 0; topPadding: 0; rightPadding: 0; bottomPadding: 0
- contentItem: ColorIcon {
- name: "../images/media-skip-forward.svg"
- }
+ imageSource: "../images/media-skip-forward.svg"
+ longpressImageSource: "../images/media-seek-forward.svg"
+ repeat: true
onClicked: {
root.executeAction("skipNext")
}
+ onLongpressed: {
+ root.executeAction("fastForward")
+ }
}
Item { Layout.fillWidth: true }
}