More refactoring and layout updates

This commit is contained in:
Joseph Donofry 2021-11-11 00:16:25 -05:00
parent e3eb87cc21
commit c5e8b2da15
No known key found for this signature in database
GPG key ID: E8A1D78EF044B0CB
6 changed files with 190 additions and 74 deletions

View file

@ -7,7 +7,7 @@ import "../ui/media"
import QtMultimedia 5.15 import QtMultimedia 5.15
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2 import QtQuick.Layouts 1.15
import im.nheko 1.0 import im.nheko 1.0
ColumnLayout { ColumnLayout {
@ -45,8 +45,8 @@ ColumnLayout {
property bool tooHigh: tempHeight > timelineRoot.height / divisor property bool tooHigh: tempHeight > timelineRoot.height / divisor
color: type == MtxEvent.VideoMessage ? Nheko.colors.window : "transparent" color: type == MtxEvent.VideoMessage ? Nheko.colors.window : "transparent"
Layout.preferredHeight: type == MtxEvent.VideoMessage ? tooHigh ? timelineRoot.height / divisor : tempHeight : 40 Layout.preferredHeight: type == MtxEvent.VideoMessage ? tooHigh ? timelineRoot.height / divisor : tempHeight : 80
Layout.preferredWidth: tooHigh ? (timelineRoot.height / divisor) / proportionalHeight : tempWidth Layout.preferredWidth: type == MtxEvent.VideoMessage ? tooHigh ? (timelineRoot.height / divisor) / proportionalHeight : tempWidth : 250
Image { Image {
anchors.fill: parent anchors.fill: parent
@ -73,11 +73,11 @@ ColumnLayout {
y: type == MtxEvent.VideoMessage ? videoOutput.contentRect.y : videoContainer.y y: type == MtxEvent.VideoMessage ? videoOutput.contentRect.y : videoContainer.y
width: type == MtxEvent.VideoMessage ? videoOutput.contentRect.width : videoContainer.width width: type == MtxEvent.VideoMessage ? videoOutput.contentRect.width : videoContainer.width
height: type == MtxEvent.VideoMessage ? videoOutput.contentRect.height : videoContainer.height height: type == MtxEvent.VideoMessage ? videoOutput.contentRect.height : videoContainer.height
playingVideo: type == MtxEvent.VideoMessage
positionValue: mxcmedia.position positionValue: mxcmedia.position
duration: mxcmedia.duration duration: mxcmedia.duration
mediaLoaded: mxcmedia.loaded mediaLoaded: mxcmedia.loaded
mediaState: mxcmedia.state mediaState: mxcmedia.state
volumeOrientation: Qt.Vertical
onPositionChanged: mxcmedia.position = position onPositionChanged: mxcmedia.position = position
onPlayPauseActivated: mxcmedia.state == MediaPlayer.PlayingState ? mxcmedia.pause() : mxcmedia.play() onPlayPauseActivated: mxcmedia.state == MediaPlayer.PlayingState ? mxcmedia.pause() : mxcmedia.play()
onLoadActivated: mxcmedia.eventId = eventId onLoadActivated: mxcmedia.eventId = eventId

View file

@ -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
}
}

View file

@ -2,10 +2,11 @@
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import "../"
import QtMultimedia 5.15 import QtMultimedia 5.15
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2 import QtQuick.Layouts 1.15
import im.nheko 1.0 import im.nheko 1.0
Item { Item {
@ -13,14 +14,14 @@ Item {
property alias desiredVolume: volumeSlider.desiredVolume property alias desiredVolume: volumeSlider.desiredVolume
property alias muted: volumeSlider.muted property alias muted: volumeSlider.muted
property alias volumeOrientation: volumeSlider.orientation property bool playingVideo: false
property var mediaState property var mediaState
property bool mediaLoaded: false property bool mediaLoaded: false
property var duration property var duration
property var positionValue: 0 property var positionValue: 0
property var position property var position
property int controlHeight: 25 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 playPauseActivated(real mouseX, real mouseY)
signal loadActivated(real mouseX, real mouseY) signal loadActivated(real mouseX, real mouseY)
@ -47,7 +48,7 @@ Item {
MouseArea { MouseArea {
id: playerMouseArea 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: { onClicked: {
control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY); control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY);
@ -60,76 +61,103 @@ Item {
propagateComposedEvents: true propagateComposedEvents: true
} }
Rectangle { ColumnLayout {
id: controlRect
// Window color with 128/255 alpha id: controlLayout
color: { opacity: control.shouldShowControls ? 1 : 0
var wc = Nheko.colors.alternateBase;
return Qt.rgba(wc.r, wc.g, wc.b, 0.5); // spacing: Nheko.paddingSmall
}
anchors.bottom: control.bottom anchors.bottom: control.bottom
anchors.left: control.left anchors.left: control.left
anchors.right: control.right anchors.right: control.right
height: 40
opacity: control.shouldShowControls ? 1 : 0
RowLayout { NhekoSlider {
anchors.fill: parent Layout.fillWidth: true
width: parent.width 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
}
// Cache/Play/pause button Rectangle {
Image { id: controlRect
id: playbackStateImage
property color controlColor: (playbackStateArea.containsMouse) ? Nheko.colors.highlight : Nheko.colors.text // Window color with 128/255 alpha
color: {
var wc = Nheko.colors.alternateBase;
return Qt.rgba(wc.r, wc.g, wc.b, 0.5);
}
fillMode: Image.PreserveAspectFit Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
Layout.preferredHeight: control.controlHeight
Layout.alignment: Qt.AlignVCenter height: 35
source: { Layout.fillWidth: true
if (control.mediaLoaded) {
if (control.mediaState == MediaPlayer.PlayingState) RowLayout {
return "image://colorimage/:/icons/icons/ui/pause-symbol.png?" + controlColor; anchors.left: controlRect.left
else anchors.bottom: controlRect.bottom
return "image://colorimage/:/icons/icons/ui/play-sign.png?" + controlColor; anchors.right: controlRect.right
} else { anchors.margins: Nheko.paddingSmall
return "image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?" + controlColor; 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
anchors.fill: parent
hoverEnabled: true
onClicked: {
control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY);
}
}
} }
MouseArea { VolumeControl {
id: playbackStateArea Layout.alignment: Qt.AlignLeft
id: volumeSlider
anchors.fill: parent orientation: Qt.Horizontal
hoverEnabled: true Layout.rightMargin: 5
onClicked: { Layout.preferredHeight: control.controlHeight
control.mediaLoaded ? control.playPauseActivated(mouseX, mouseY) : control.loadActivated(mouseX, mouseY);
}
} }
} Label {
Layout.alignment: Qt.AlignRight
Label { text: (!control.mediaLoaded) ? "-/-" : (durationToString(control.positionValue) + "/" + durationToString(control.duration))
text: (!control.mediaLoaded) ? "-/-" : (durationToString(control.positionValue) + "/" + durationToString(control.duration)) color: Nheko.colors.text
color: Nheko.colors.text }
}
Slider { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumWidth: 50 }
height: control.controlHeight
value: control.positionValue
onMoved: control.position = value
from: 0
to: control.duration
}
VolumeControl {
id: volumeSlider
Layout.rightMargin: 5
Layout.preferredHeight: control.controlHeight
} }
} }

View file

@ -2,9 +2,12 @@
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import "../"
import QtMultimedia 5.15 import QtMultimedia 5.15
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import im.nheko 1.0 import im.nheko 1.0
// Volume slider activator // Volume slider activator
@ -17,6 +20,7 @@ Image {
property alias controlsVisible: volumeSliderRect.visible property alias controlsVisible: volumeSliderRect.visible
property bool muted: false property bool muted: false
property color controlColor: (volumeImageArea.containsMouse) ? Nheko.colors.highlight : Nheko.colors.text 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 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 fillMode: Image.PreserveAspectFit
@ -45,32 +49,38 @@ Image {
id: volumeSliderRect id: volumeSliderRect
opacity: (visible) ? 1 : 0 opacity: (visible) ? 1 : 0
anchors.bottom: volumeImage.top anchors.bottom: volumeSlider.orientation == Qt.Vertical ? volumeImage.top : undefined
anchors.bottomMargin: 10 anchors.left: volumeSlider.orientation == Qt.Vertical ? undefined : volumeImage.right
anchors.horizontalCenter: volumeImage.horizontalCenter anchors.horizontalCenter: volumeSlider.orientation == Qt.Vertical ? volumeImage.horizontalCenter : undefined
anchors.verticalCenter: volumeSlider.orientation == Qt.Vertical ? undefined : volumeImage.verticalCenter
color: { color: {
var wc = Nheko.colors.window; if (volumeSlider.orientation == Qt.Vertical) {
return Qt.rgba(wc.r, wc.g, wc.b, 0.5); 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 /* TODO: base width on the slider width (some issue with it not having a geometry
when using the width here?) */ when using the width here?) */
width: volumeImage.width * 0.7 width: volumeSlider.orientation == Qt.Vertical ? volumeImage.width * 0.7 : 100
radius: volumeSlider.width / 2 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 visible: volumeImageArea.containsMouse || volumeSliderHideTimer.running || volumeSliderRectMouseArea.containsMouse
Slider { NhekoSlider {
// TODO: the slider is slightly off-center on the left for some reason... // TODO: the slider is slightly off-center on the left for some reason...
id: volumeSlider id: volumeSlider
sliderWidth: 8
sliderHeight: 8
// Desired value to avoid loop onMoved -> media.volume -> value -> onMoved... // Desired value to avoid loop onMoved -> media.volume -> value -> onMoved...
property real desiredVolume: QtMultimedia.convertVolume(volumeSlider.value, QtMultimedia.LogarithmicVolumeScale, QtMultimedia.LinearVolumeScale) property real desiredVolume: QtMultimedia.convertVolume(volumeSlider.value, QtMultimedia.LogarithmicVolumeScale, QtMultimedia.LinearVolumeScale)
value: 1 value: 1
anchors.fill: volumeSliderRect anchors.fill: volumeSliderRect
anchors.bottomMargin: volumeSliderRect.height * 0.1 anchors.horizontalCenter: orientation == Qt.Vertical ? volumeSliderRect.horizontalCenter : undefined
anchors.topMargin: volumeSliderRect.height * 0.1 anchors.verticalCenter: orientation == Qt.Vertical ? undefined : volumeSliderRect.verticalCenter
anchors.horizontalCenter: volumeSliderRect.horizontalCenter
orientation: Qt.Vertical orientation: Qt.Vertical
onDesiredVolumeChanged: { onDesiredVolumeChanged: {
volumeImage.muted = !(desiredVolume > 0); volumeImage.muted = !(desiredVolume > 0);
@ -101,7 +111,6 @@ Image {
} }
} }
// TODO: figure out a better way to put the slider popup above controlRect
} }

View file

@ -1,3 +1,4 @@
module im.nheko.UI module im.nheko.UI
NhekoSlider 1.0 NhekoSlider.qml
Ripple 1.0 Ripple.qml Ripple 1.0 Ripple.qml
Spinner 1.0 Spinner.qml Spinner 1.0 Spinner.qml

View file

@ -180,6 +180,7 @@
<file>qml/dialogs/UserProfile.qml</file> <file>qml/dialogs/UserProfile.qml</file>
<file>qml/emoji/EmojiPicker.qml</file> <file>qml/emoji/EmojiPicker.qml</file>
<file>qml/emoji/StickerPicker.qml</file> <file>qml/emoji/StickerPicker.qml</file>
<file>qml/ui/NhekoSlider.qml</file>
<file>qml/ui/Ripple.qml</file> <file>qml/ui/Ripple.qml</file>
<file>qml/ui/Spinner.qml</file> <file>qml/ui/Spinner.qml</file>
<file>qml/ui/animations/BlinkAnimation.qml</file> <file>qml/ui/animations/BlinkAnimation.qml</file>