summary refs log tree commit diff
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/qml/delegates/PlayableMediaMessage.qml8
-rw-r--r--resources/qml/ui/NhekoSlider.qml77
-rw-r--r--resources/qml/ui/media/MediaControls.qml146
-rw-r--r--resources/qml/ui/media/VolumeControl.qml33
-rw-r--r--resources/qml/ui/qmldir1
-rw-r--r--resources/res.qrc1
6 files changed, 191 insertions, 75 deletions
diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml
index e6bcdcac..2b4c4d49 100644
--- a/resources/qml/delegates/PlayableMediaMessage.qml
+++ b/resources/qml/delegates/PlayableMediaMessage.qml
@@ -7,7 +7,7 @@ import "../ui/media"
 import QtMultimedia 5.15
 import QtQuick 2.15
 import QtQuick.Controls 2.15
-import QtQuick.Layouts 1.2
+import QtQuick.Layouts 1.15
 import im.nheko 1.0
 
 ColumnLayout {
@@ -45,8 +45,8 @@ ColumnLayout {
         property bool tooHigh: tempHeight > timelineRoot.height / divisor
 
         color: type == MtxEvent.VideoMessage ? Nheko.colors.window : "transparent"
-        Layout.preferredHeight: type == MtxEvent.VideoMessage ? tooHigh ? timelineRoot.height / divisor : tempHeight : 40
-        Layout.preferredWidth: tooHigh ? (timelineRoot.height / divisor) / proportionalHeight : tempWidth
+        Layout.preferredHeight: type == MtxEvent.VideoMessage ? tooHigh ? timelineRoot.height / divisor : tempHeight : 80
+        Layout.preferredWidth: type == MtxEvent.VideoMessage ? tooHigh ? (timelineRoot.height / divisor) / proportionalHeight : tempWidth : 250
 
         Image {
             anchors.fill: parent
@@ -73,11 +73,11 @@ ColumnLayout {
                 y: type == MtxEvent.VideoMessage ? videoOutput.contentRect.y : videoContainer.y
                 width: type == MtxEvent.VideoMessage ? videoOutput.contentRect.width : videoContainer.width
                 height: type == MtxEvent.VideoMessage ? videoOutput.contentRect.height : videoContainer.height
+                playingVideo: type == MtxEvent.VideoMessage
                 positionValue: mxcmedia.position
                 duration: mxcmedia.duration
                 mediaLoaded: mxcmedia.loaded
                 mediaState: mxcmedia.state
-                volumeOrientation: Qt.Vertical
                 onPositionChanged: mxcmedia.position = position
                 onPlayPauseActivated: mxcmedia.state == MediaPlayer.PlayingState ? mxcmedia.pause() : mxcmedia.play()
                 onLoadActivated: mxcmedia.eventId = eventId
diff --git a/resources/qml/ui/NhekoSlider.qml b/resources/qml/ui/NhekoSlider.qml
new file mode 100644
index 00000000..887cb80c
--- /dev/null
+++ b/resources/qml/ui/NhekoSlider.qml
@@ -0,0 +1,77 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import im.nheko 1.0
+
+Slider {
+    id: slider
+
+    property real sliderWidth
+    property real sliderHeight
+    property bool alwaysShowSlider: true
+
+    anchors.bottomMargin: orientation == Qt.Vertical ? Nheko.paddingMedium : undefined
+    anchors.topMargin: orientation == Qt.Vertical ? Nheko.paddingMedium : undefined
+    anchors.leftMargin: orientation == Qt.Vertical ? undefined : Nheko.paddingMedium
+    anchors.rightMargin: orientation == Qt.Vertical ? undefined : Nheko.paddingMedium
+
+    background: Rectangle {
+        x: slider.leftPadding + (slider.orientation == Qt.Vertical ? slider.availableWidth / 2 - width / 2 : 0)
+        y: slider.topPadding + (slider.orientation == Qt.Vertical ? 0 : slider.availableHeight / 2 - height / 2)
+        // implicitWidth: slider.orientation == Qt.Vertical ? 8 : 100
+        // implicitHeight: slider.orientation == Qt.Vertical ? 100 : 8
+        width: slider.orientation == Qt.Vertical ? sliderWidth : slider.availableWidth
+        height: slider.orientation == Qt.Vertical ? slider.availableHeight : sliderHeight
+        radius: 2
+        color: {
+            if (slider.orientation == Qt.Vertical) {
+                return Nheko.colors.highlight;
+            } else {
+                var col = Nheko.colors.buttonText;
+                return Qt.rgba(col.r, col.g, col.b, 0.5);
+            }
+        }
+        border.color: {
+            var col = Nheko.colors.base;
+            return Qt.rgba(col.r, col.g, col.b, 0.5);
+        }
+
+        Rectangle {
+            width: slider.orientation == Qt.Vertical ? parent.width : slider.visualPosition * parent.width
+            height: slider.orientation == Qt.Vertical ? slider.visualPosition * parent.height : parent.height
+            color: {
+                if (slider.orientation == Qt.Vertical) {
+                    return Nheko.colors.buttonText;
+                } else {
+                    return Nheko.colors.highlight;
+                }
+            }
+            radius: 2
+        }
+
+    }
+
+    handle: Rectangle {
+        x: {
+            if (slider.orientation == Qt.Vertical)
+                return slider.leftPadding + slider.availableWidth / 2 - width / 2;
+            else
+                return slider.leftPadding + slider.visualPosition * (slider.availableWidth - width);
+        }
+        y: {
+            if (slider.orientation == Qt.Vertical)
+                return slider.topPadding + slider.visualPosition * (slider.availableHeight - height);
+            else
+                return slider.topPadding + slider.availableHeight / 2 - height / 2;
+        }
+        implicitWidth: 16
+        implicitHeight: 16
+        radius: slider.width / 2
+        color: Nheko.colors.highlight
+        visible:  alwaysShowSlider || slider.hovered || slider.pressed || Settings.mobileMode
+    }
+
+}
diff --git a/resources/qml/ui/media/MediaControls.qml b/resources/qml/ui/media/MediaControls.qml
index ec522391..b529462d 100644
--- a/resources/qml/ui/media/MediaControls.qml
+++ b/resources/qml/ui/media/MediaControls.qml
@@ -2,10 +2,11 @@
 //
 // SPDX-License-Identifier: GPL-3.0-or-later
 
+import "../"
 import QtMultimedia 5.15
 import QtQuick 2.15
 import QtQuick.Controls 2.15
-import QtQuick.Layouts 1.2
+import QtQuick.Layouts 1.15
 import im.nheko 1.0
 
 Item {
@@ -13,14 +14,14 @@ Item {
 
     property alias desiredVolume: volumeSlider.desiredVolume
     property alias muted: volumeSlider.muted
-    property alias volumeOrientation: volumeSlider.orientation
+    property bool playingVideo: false
     property var mediaState
     property bool mediaLoaded: false
     property var duration
     property var positionValue: 0
     property var position
     property int controlHeight: 25
-    property bool shouldShowControls: playerMouseArea.shouldShowControls || volumeSlider.controlsVisible
+    property bool shouldShowControls: !playingVideo || playerMouseArea.shouldShowControls || volumeSlider.controlsVisible
 
     signal playPauseActivated(real mouseX, real mouseY)
     signal loadActivated(real mouseX, real mouseY)
@@ -47,7 +48,7 @@ Item {
     MouseArea {
         id: playerMouseArea
 
-        property bool shouldShowControls: (containsMouse && controlHideTimer.running) || (control.mediaState != MediaPlayer.PlayingState) || controlRect.contains(mapToItem(controlRect, mouseX, mouseY))
+        property bool shouldShowControls: (containsMouse && controlHideTimer.running) || (control.mediaState != MediaPlayer.PlayingState) || controlLayout.contains(mapToItem(controlLayout, mouseX, mouseY))
 
         onClicked: {
             control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY);
@@ -60,76 +61,103 @@ Item {
         propagateComposedEvents: true
     }
 
-    Rectangle {
-        id: controlRect
+    ColumnLayout {
 
-        // Window color with 128/255 alpha
-        color: {
-            var wc = Nheko.colors.alternateBase;
-            return Qt.rgba(wc.r, wc.g, wc.b, 0.5);
-        }
+        id: controlLayout
+        opacity: control.shouldShowControls ? 1 : 0
+
+        // spacing: Nheko.paddingSmall
         anchors.bottom: control.bottom
         anchors.left: control.left
         anchors.right: control.right
-        height: 40
-        opacity: control.shouldShowControls ? 1 : 0
 
-        RowLayout {
-            anchors.fill: parent
-            width: parent.width
-
-            // Cache/Play/pause button
-            Image {
-                id: playbackStateImage
-
-                property color controlColor: (playbackStateArea.containsMouse) ? Nheko.colors.highlight : Nheko.colors.text
-
-                fillMode: Image.PreserveAspectFit
-                Layout.preferredHeight: control.controlHeight
-                Layout.alignment: Qt.AlignVCenter
-                source: {
-                    if (control.mediaLoaded) {
-                        if (control.mediaState == MediaPlayer.PlayingState)
-                            return "image://colorimage/:/icons/icons/ui/pause-symbol.png?" + controlColor;
-                        else
-                            return "image://colorimage/:/icons/icons/ui/play-sign.png?" + controlColor;
-                    } else {
-                        return "image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?" + controlColor;
+        NhekoSlider {
+            Layout.fillWidth: true
+            Layout.minimumWidth: 50
+            Layout.leftMargin: Nheko.paddingMedium
+            Layout.rightMargin: Nheko.paddingMedium
+            height: control.controlHeight
+            value: control.positionValue
+            onMoved: control.position = value
+            from: 0
+            to: control.duration
+            sliderHeight: 8
+            alwaysShowSlider: false
+        }
+
+        Rectangle {
+            id: controlRect
+
+            // Window color with 128/255 alpha
+            color: {
+                var wc = Nheko.colors.alternateBase;
+                return Qt.rgba(wc.r, wc.g, wc.b, 0.5);
+            }
+
+            Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
+
+            height: 35
+            Layout.fillWidth: true
+
+            RowLayout {
+                anchors.left: controlRect.left
+                anchors.bottom: controlRect.bottom
+                anchors.right: controlRect.right
+                anchors.margins: Nheko.paddingSmall
+                anchors.verticalCenter: controlRect.verticalCenter
+                spacing: Nheko.paddingSmall
+
+                // Cache/Play/pause button
+                Image {
+                    Layout.alignment: Qt.AlignLeft
+                    id: playbackStateImage
+
+                    property color controlColor: (playbackStateArea.containsMouse) ? Nheko.colors.highlight : Nheko.colors.text
+
+                    fillMode: Image.PreserveAspectFit
+                    Layout.preferredHeight: control.controlHeight
+                    source: {
+                        if (control.mediaLoaded) {
+                            if (control.mediaState == MediaPlayer.PlayingState)
+                                return "image://colorimage/:/icons/icons/ui/pause-symbol.png?" + controlColor;
+                            else
+                                return "image://colorimage/:/icons/icons/ui/play-sign.png?" + controlColor;
+                        } else {
+                            return "image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?" + controlColor;
+                        }
                     }
-                }
 
-                MouseArea {
-                    id: playbackStateArea
+                    MouseArea {
+                        id: playbackStateArea
 
-                    anchors.fill: parent
-                    hoverEnabled: true
-                    onClicked: {
-                        control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY);
+                        anchors.fill: parent
+                        hoverEnabled: true
+                        onClicked: {
+                            control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY);
+                        }
                     }
+
                 }
 
-            }
+                VolumeControl {
+                    Layout.alignment: Qt.AlignLeft
+                    id: volumeSlider
+                    orientation: Qt.Horizontal
+                    Layout.rightMargin: 5
+                    Layout.preferredHeight: control.controlHeight
+                }
 
-            Label {
-                text: (!control.mediaLoaded) ? "-/-" : (durationToString(control.positionValue) + "/" + durationToString(control.duration))
-                color: Nheko.colors.text
-            }
+                Label {
+                    Layout.alignment: Qt.AlignRight
 
-            Slider {
-                Layout.fillWidth: true
-                Layout.minimumWidth: 50
-                height: control.controlHeight
-                value: control.positionValue
-                onMoved: control.position = value
-                from: 0
-                to: control.duration
-            }
+                    text: (!control.mediaLoaded) ? "-/-" : (durationToString(control.positionValue) + "/" + durationToString(control.duration))
+                    color: Nheko.colors.text
+                }
 
-            VolumeControl {
-                id: volumeSlider
+                Item {
+                    Layout.fillWidth: true
+                }
 
-                Layout.rightMargin: 5
-                Layout.preferredHeight: control.controlHeight
             }
 
         }
diff --git a/resources/qml/ui/media/VolumeControl.qml b/resources/qml/ui/media/VolumeControl.qml
index cd844ed5..e87550ac 100644
--- a/resources/qml/ui/media/VolumeControl.qml
+++ b/resources/qml/ui/media/VolumeControl.qml
@@ -2,9 +2,12 @@
 //
 // SPDX-License-Identifier: GPL-3.0-or-later
 
+import "../"
+
 import QtMultimedia 5.15
 import QtQuick 2.15
 import QtQuick.Controls 2.15
+
 import im.nheko 1.0
 
 // Volume slider activator
@@ -17,6 +20,7 @@ Image {
     property alias controlsVisible: volumeSliderRect.visible
     property bool muted: false
     property color controlColor: (volumeImageArea.containsMouse) ? Nheko.colors.highlight : Nheko.colors.text
+    width: sourceSize.width + volumeSliderRect.implicitWidth
 
     source: (desiredVolume > 0 && !muted) ? "image://colorimage/:/icons/icons/ui/volume-up.png?" + controlColor : "image://colorimage/:/icons/icons/ui/volume-off-indicator.png?" + controlColor
     fillMode: Image.PreserveAspectFit
@@ -45,32 +49,38 @@ Image {
         id: volumeSliderRect
 
         opacity: (visible) ? 1 : 0
-        anchors.bottom: volumeImage.top
-        anchors.bottomMargin: 10
-        anchors.horizontalCenter: volumeImage.horizontalCenter
+        anchors.bottom: volumeSlider.orientation == Qt.Vertical ? volumeImage.top : undefined
+        anchors.left: volumeSlider.orientation == Qt.Vertical ? undefined : volumeImage.right
+        anchors.horizontalCenter: volumeSlider.orientation == Qt.Vertical ? volumeImage.horizontalCenter : undefined
+        anchors.verticalCenter: volumeSlider.orientation == Qt.Vertical ? undefined : volumeImage.verticalCenter
         color: {
-            var wc = Nheko.colors.window;
-            return Qt.rgba(wc.r, wc.g, wc.b, 0.5);
+            if (volumeSlider.orientation == Qt.Vertical) {
+                var wc = Nheko.colors.window;
+                return Qt.rgba(wc.r, wc.g, wc.b, 0.5);
+            } else {
+                return "transparent";
+            }
         }
         /* TODO: base width on the slider width (some issue with it not having a geometry
         when using the width here?) */
-        width: volumeImage.width * 0.7
+        width: volumeSlider.orientation == Qt.Vertical ? volumeImage.width * 0.7 : 100
         radius: volumeSlider.width / 2
-        height: controlRect.height * 2 //100
+        height: volumeSlider.orientation == Qt.Vertical ? 100 : volumeImage.height * 0.7
         visible: volumeImageArea.containsMouse || volumeSliderHideTimer.running || volumeSliderRectMouseArea.containsMouse
 
-        Slider {
+        NhekoSlider {
             // TODO: the slider is slightly off-center on the left for some reason...
             id: volumeSlider
 
+            sliderWidth: 8
+            sliderHeight: 8
             // Desired value to avoid loop onMoved -> media.volume -> value -> onMoved...
             property real desiredVolume: QtMultimedia.convertVolume(volumeSlider.value, QtMultimedia.LogarithmicVolumeScale, QtMultimedia.LinearVolumeScale)
 
             value: 1
             anchors.fill: volumeSliderRect
-            anchors.bottomMargin: volumeSliderRect.height * 0.1
-            anchors.topMargin: volumeSliderRect.height * 0.1
-            anchors.horizontalCenter: volumeSliderRect.horizontalCenter
+            anchors.horizontalCenter: orientation == Qt.Vertical ? volumeSliderRect.horizontalCenter : undefined
+            anchors.verticalCenter: orientation == Qt.Vertical ? undefined : volumeSliderRect.verticalCenter
             orientation: Qt.Vertical
             onDesiredVolumeChanged: {
                 volumeImage.muted = !(desiredVolume > 0);
@@ -101,7 +111,6 @@ Image {
             }
 
         }
-        // TODO: figure out a better way to put the slider popup above controlRect
 
     }
 
diff --git a/resources/qml/ui/qmldir b/resources/qml/ui/qmldir
index 831a723d..a2ce7514 100644
--- a/resources/qml/ui/qmldir
+++ b/resources/qml/ui/qmldir
@@ -1,3 +1,4 @@
 module im.nheko.UI
+NhekoSlider 1.0 NhekoSlider.qml
 Ripple 1.0 Ripple.qml
 Spinner 1.0 Spinner.qml
\ No newline at end of file
diff --git a/resources/res.qrc b/resources/res.qrc
index 538095ab..4e243251 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -180,6 +180,7 @@
         <file>qml/dialogs/UserProfile.qml</file>
         <file>qml/emoji/EmojiPicker.qml</file>
         <file>qml/emoji/StickerPicker.qml</file>
+        <file>qml/ui/NhekoSlider.qml</file>
         <file>qml/ui/Ripple.qml</file>
         <file>qml/ui/Spinner.qml</file>
         <file>qml/ui/animations/BlinkAnimation.qml</file>