diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index 7a3e5967..aa075064 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -187,6 +187,7 @@ ui/devicepages/DeviceBrowserPage.qml ui/devicelistpages/MediaDeviceListPage.qml ui/components/MediaControls.qml + ui/components/ClosableArrowAnimation.qml ui/components/MediaArtworkImage.qml ui/components/BrowserContextMenu.qml ui/magic/SelectBrowserItemActionPage.qml diff --git a/nymea-app/ui/components/ClosableArrowAnimation.qml b/nymea-app/ui/components/ClosableArrowAnimation.qml new file mode 100644 index 00000000..ada19265 --- /dev/null +++ b/nymea-app/ui/components/ClosableArrowAnimation.qml @@ -0,0 +1,48 @@ +import QtQuick 2.0 + +Item { + id: arrows + width: app.iconSize * 2 + height: parent.height * .6 + clip: true + visible: state !== "" + + state: "" // "opening", "closing" or "" + + readonly property bool up: arrows.state === "opening" + + // NumberAnimation doesn't reload to/from while it's running. If we switch from closing to opening or vice versa + // we need to somehow stop and start the animation + property bool animationHack: true + onAnimationHackChanged: { + if (!animationHack) hackTimer.start(); + } + Timer { id: hackTimer; interval: 1; onTriggered: arrows.animationHack = true } + onStateChanged: arrows.animationHack = false + + NumberAnimation { + target: arrowColumn + property: "y" + duration: 500 + easing.type: Easing.Linear + from: arrows.up ? app.iconSize : -app.iconSize + to: arrows.up ? -app.iconSize : app.iconSize + loops: Animation.Infinite + running: arrows.animationHack && (arrows.state === "opening" || arrows.state === "closing") + } + + Column { + id: arrowColumn + width: parent.width + + Repeater { + model: arrows.height / app.iconSize + 1 + ColorIcon { + name: arrows.up ? "../images/up.svg" : "../images/down.svg" + width: parent.width + height: width + color: app.accentColor + } + } + } +} diff --git a/nymea-app/ui/components/ShutterControls.qml b/nymea-app/ui/components/ShutterControls.qml index d83f4e52..c61123f4 100644 --- a/nymea-app/ui/components/ShutterControls.qml +++ b/nymea-app/ui/components/ShutterControls.qml @@ -14,6 +14,8 @@ RowLayout { property bool invert: false + signal activated(string button); + ItemDelegate { Layout.preferredWidth: app.iconSize * 2 Layout.preferredHeight: width @@ -24,7 +26,10 @@ RowLayout { name: root.invert ? "../images/down.svg" : "../images/up.svg" color: root.openState && root.openState.value === "opening" ? Material.accent : keyColor } - onClicked: engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("open").id) + onClicked: { + engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("open").id) + root.activated("open") + } } @@ -39,7 +44,10 @@ RowLayout { anchors.margins: app.margins name: "../images/media-playback-stop.svg" } - onClicked: engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("stop").id) + onClicked: { + engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("stop").id) + root.activated("stop") + } } ItemDelegate { @@ -52,6 +60,9 @@ RowLayout { name: root.invert ? "../images/up.svg" : "../images/down.svg" color: root.openState && root.openState.value === "closing" ? Material.accent : keyColor } - onClicked: engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("close").id) + onClicked: { + engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("close").id) + root.activated("close") + } } } diff --git a/nymea-app/ui/devicepages/ShutterDevicePage.qml b/nymea-app/ui/devicepages/ShutterDevicePage.qml index 312bca42..b7999789 100644 --- a/nymea-app/ui/devicepages/ShutterDevicePage.qml +++ b/nymea-app/ui/devicepages/ShutterDevicePage.qml @@ -22,8 +22,26 @@ DevicePageBase { id: shutterImage Layout.preferredWidth: root.landscape ? Math.min(parent.width - shutterControlsContainer.width, parent.height) - app.margins : parent.width Layout.preferredHeight: width - name: "../images/shutter/shutter-" + app.pad(Math.round(root.percentageState.value / 10) * 10, 3) + ".svg" - visible: isExtended + name: "../images/shutter/shutter-" + app.pad(isExtended ? Math.round(root.percentageState.value / 10) * 10 : 50, 3) + ".svg" + + ClosableArrowAnimation { + id: arrowAnimation + anchors.centerIn: parent + + onStateChanged: { + if (state != "") { + animationTimer.start(); + } + } + + Timer { + id: animationTimer + running: false + interval: 5000 + repeat: false + onTriggered: parent.state = "" + } + } } Item { @@ -73,6 +91,15 @@ DevicePageBase { device: root.device anchors.horizontalCenter: parent.horizontalCenter spacing: (parent.width - app.iconSize*2*children.length) / (children.length - 1) + onActivated: { + if (button == "open") { + arrowAnimation.state = "opening" + } else if (button == "close") { + arrowAnimation.state = "closing" + } else { + arrowAnimation.state = "" + } + } } } }