diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc
index a5c271a4..1bd386d1 100644
--- a/nymea-app/images.qrc
+++ b/nymea-app/images.qrc
@@ -161,5 +161,11 @@
ui/images/mqtt.svg
ui/images/sensors/co2.svg
ui/images/sensors/noise.svg
+ ui/images/media-playlist-repeat-one.svg
+ ui/images/media-playlist-repeat.svg
+ ui/images/media-playlist-shuffle.svg
+ ui/images/media-playlist.svg
+ ui/images/stock_music.svg
+ ui/images/stock_video.svg
diff --git a/nymea-app/ui/devicepages/MediaDevicePage.qml b/nymea-app/ui/devicepages/MediaDevicePage.qml
index 58a4ba27..e68a017c 100644
--- a/nymea-app/ui/devicepages/MediaDevicePage.qml
+++ b/nymea-app/ui/devicepages/MediaDevicePage.qml
@@ -1,5 +1,6 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
+import QtQuick.Controls.Material 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
@@ -8,23 +9,246 @@ import "../customviews"
DevicePageBase {
id: root
- ColumnLayout {
+ function stateValue(name) {
+ var stateType = root.deviceClass.stateTypes.findByName(name);
+ if (!stateType) return null
+ return root.device.states.getState(stateType.id).value
+ }
+
+ function executeAction(actionName, params) {
+ var actionTypeId = deviceClass.actionTypes.findByName(actionName).id;
+ print("executing", device, device.id, actionTypeId, actionName, deviceClass.actionTypes, params)
+ engine.deviceManager.executeAction(device.id, actionTypeId, params)
+ }
+
+ readonly property State playbackState: device.states.getState(deviceClass.stateTypes.findByName("playbackStatus").id)
+
+ GridLayout {
id: contentColumn
anchors.fill: parent
- spacing: app.margins
+ anchors.margins: app.margins
+ columns: app.landscape ? 2 : 1
+ columnSpacing: app.margins
+ rowSpacing: app.margins
- ExtendedVolumeController {
+ Pane {
Layout.fillWidth: true
- device: root.device
- deviceClass: root.deviceClass
-// visible: deviceClass.interfaces.indexOf("extendedvolumecontroller") >= 0
+ Layout.fillHeight: true
+ Material.elevation: 2
+ padding: 0
+
+ contentItem: Rectangle {
+ color: app.foregroundColor
+
+ Image {
+ id: artworkImage
+ anchors.fill: parent
+ fillMode: Image.PreserveAspectFit
+ source: root.stateValue("artwork")
+ }
+
+ ColorIcon {
+ id: fallback
+ anchors.fill: parent
+ anchors.margins: app.margins * 2
+ name: root.stateValue("playerType") === "video" ? "../images/stock_video.svg" : "../images/stock_music.svg"
+ visible: artworkImage.status !== Image.Ready || artworkImage.source === ""
+ color: app.primaryColor
+ }
+ }
}
- MediaControllerView {
+ ColumnLayout {
Layout.fillWidth: true
- device: root.device
- deviceClass: root.deviceClass
- visible: root.deviceClass.interfaces.indexOf("mediacontroller") >= 0
+ spacing: app.margins
+
+ Label {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ elide: Text.ElideRight
+ font.pixelSize: app.largeFont
+ font.bold: true
+ text: root.stateValue("title")
+ }
+ Label {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ elide: Text.ElideRight
+ text: root.stateValue("artist")
+ }
+ Label {
+ Layout.fillWidth: true
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ elide: Text.ElideRight
+ text: root.stateValue("collection")
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Item { Layout.fillWidth: true }
+
+ ItemDelegate {
+ Layout.preferredHeight: app.iconSize
+ Layout.preferredWidth: height
+ leftPadding: 0; topPadding: 0; rightPadding: 0; bottomPadding: 0
+ contentItem: ColorIcon {
+ name: "../images/media-skip-backward.svg"
+ }
+ onClicked: {
+ root.executeAction("skipBack")
+ }
+ }
+
+ Item { Layout.fillWidth: true }
+ ItemDelegate {
+ 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"
+ }
+ onClicked: {
+ if (root,playbackState.value === "Playing") {
+ root.executeAction("pause")
+ } else {
+ root.executeAction("play")
+ }
+ }
+ }
+ Item { Layout.fillWidth: true }
+ ItemDelegate {
+ Layout.preferredHeight: app.iconSize
+ Layout.preferredWidth: height
+ leftPadding: 0; topPadding: 0; rightPadding: 0; bottomPadding: 0
+ contentItem: ColorIcon {
+ name: "../images/media-skip-forward.svg"
+ }
+ onClicked: {
+ root.executeAction("skipNext")
+ }
+ }
+ Item { Layout.fillWidth: true }
+ }
+ }
+ }
+
+ Component {
+ id: volumeSliderPaneComponent
+ Dialog {
+
+ leftPadding: 0
+ topPadding: app.margins / 2
+ rightPadding: 0
+ bottomPadding: app.margins / 2
+
+ contentItem: ColumnLayout {
+ Slider {
+ Layout.fillHeight: true
+ orientation: Qt.Vertical
+ from: 0
+ to: 100
+ value: root.stateValue("volume")
+ onMoved: {
+ var params = []
+ var volParam = {}
+ volParam["paramTypeId"] = root.deviceClass.actionTypes.findByName("volume").id
+ volParam["value"] = value;
+ params.push(volParam)
+ root.executeAction("volume", params);
+ }
+ }
+ HeaderButton {
+ imageSource: "../images/audio-speakers-muted-symbolic.svg"
+ color: root.stateValue("mute") ? app.accentColor : keyColor
+ onClicked: {
+ var params = []
+ var muteParam = {}
+ muteParam["paramTypeId"] = root.deviceClass.actionTypes.findByName("mute").id
+ muteParam["value"] = !root.stateValue("mute");
+ params.push(muteParam)
+ root.executeAction("mute", params);
+ }
+ }
+ }
+ }
+ }
+
+ footer: Pane {
+ Material.elevation: 1
+ height: 50
+ padding: 0
+ contentItem: RowLayout {
+// Item {
+// Layout.fillWidth: true; Layout.fillHeight: true
+// HeaderButton {
+// anchors.centerIn: parent
+// imageSource: "../images/media-playlist.svg"
+// }
+// }
+ Item {
+ Layout.fillWidth: true; Layout.fillHeight: true
+ visible: root.deviceClass.interfaces.indexOf("shufflerepeat") >= 0
+ HeaderButton {
+ anchors.centerIn: parent
+ imageSource: root.stateValue("repeat") === "One" ? "../images/media-playlist-repeat-one.svg" : "../images/media-playlist-repeat.svg"
+ color: root.stateValue("repeat") === "None" ? keyColor : app.accentColor
+ property var allowedValues: ["None", "All", "One"]
+ onClicked: {
+ var params = []
+ var param = {}
+ param["paramTypeId"] = root.deviceClass.actionTypes.findByName("repeat").id;
+ param["value"] = allowedValues[(allowedValues.indexOf(root.stateValue("repeat")) + 1) % 3]
+ params.push(param)
+ root.executeAction("repeat", params)
+ }
+ }
+ }
+ Item {
+ Layout.fillWidth: true; Layout.fillHeight: true
+ visible: root.deviceClass.interfaces.indexOf("shufflerepeat") >= 0
+ HeaderButton {
+ anchors.centerIn: parent
+ imageSource: "../images/media-playlist-shuffle.svg"
+ color: root.stateValue("shuffle") ? app.accentColor: keyColor
+ onClicked: {
+ var params = []
+ var param = {}
+ param["paramTypeId"] = root.deviceClass.actionTypes.findByName("shuffle").id;
+ param["value"] = !root.stateValue("shuffle")
+ params.push(param)
+ root.executeAction("shuffle", params)
+ }
+ }
+ }
+ Item {
+ id: volumeButtonContainer
+ Layout.fillWidth: true; Layout.fillHeight: true
+ HeaderButton {
+ id: volumeButton
+ anchors.centerIn: parent
+ imageSource: "../images/audio-speakers-symbolic.svg"
+ onClicked: {
+ print("...");
+ print(volumeButton.x, volumeButton.y)
+ print(Qt.point(volumeButton.x, volumeButton.y))
+ print(volumeButton.mapToItem(root, volumeButton.x,0))
+ var buttonPosition = root.mapFromItem(volumeButtonContainer, volumeButton.x, 0)
+ var sliderHeight = 200
+ var props = {}
+ props["x"] = buttonPosition.x
+ props["y"] = root.height - sliderHeight - root.footer.height
+ props["height"] = sliderHeight
+ var sliderPane = volumeSliderPaneComponent.createObject(root, props)
+ sliderPane.open()
+ }
+ }
+ }
}
}
}
diff --git a/nymea-app/ui/images/media-playlist-repeat-one.svg b/nymea-app/ui/images/media-playlist-repeat-one.svg
new file mode 100644
index 00000000..194ffb94
--- /dev/null
+++ b/nymea-app/ui/images/media-playlist-repeat-one.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/nymea-app/ui/images/media-playlist-repeat.svg b/nymea-app/ui/images/media-playlist-repeat.svg
new file mode 100644
index 00000000..54a2d0e4
--- /dev/null
+++ b/nymea-app/ui/images/media-playlist-repeat.svg
@@ -0,0 +1,18 @@
+
+
+
diff --git a/nymea-app/ui/images/media-playlist-shuffle.svg b/nymea-app/ui/images/media-playlist-shuffle.svg
new file mode 100644
index 00000000..d16487d5
--- /dev/null
+++ b/nymea-app/ui/images/media-playlist-shuffle.svg
@@ -0,0 +1,170 @@
+
+
+
+
diff --git a/nymea-app/ui/images/media-playlist.svg b/nymea-app/ui/images/media-playlist.svg
new file mode 100644
index 00000000..3ab686d4
--- /dev/null
+++ b/nymea-app/ui/images/media-playlist.svg
@@ -0,0 +1,193 @@
+
+
+
+
diff --git a/nymea-app/ui/images/stock_music.svg b/nymea-app/ui/images/stock_music.svg
new file mode 100644
index 00000000..b43bc37d
--- /dev/null
+++ b/nymea-app/ui/images/stock_music.svg
@@ -0,0 +1,173 @@
+
+
+
+
diff --git a/nymea-app/ui/images/stock_video.svg b/nymea-app/ui/images/stock_video.svg
new file mode 100644
index 00000000..56c5a4f4
--- /dev/null
+++ b/nymea-app/ui/images/stock_video.svg
@@ -0,0 +1,164 @@
+
+
+
+