Port to declarative type registration
This commit is contained in:
368
src/qml/VideoDelegate.qml
Normal file
368
src/qml/VideoDelegate.qml
Normal file
@@ -0,0 +1,368 @@
|
||||
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import QtMultimedia
|
||||
import Qt.labs.platform as Platform
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.neochat
|
||||
|
||||
/**
|
||||
* @brief A timeline delegate for a video message.
|
||||
*
|
||||
* @inherit MessageDelegate
|
||||
*/
|
||||
MessageDelegate {
|
||||
id: root
|
||||
|
||||
/**
|
||||
* @brief The media info for the event.
|
||||
*
|
||||
* This should consist of the following:
|
||||
* - source - The mxc URL for the media.
|
||||
* - mimeType - The MIME type of the media (should be video/xxx for this delegate).
|
||||
* - mimeIcon - The MIME icon name (should be video-xxx).
|
||||
* - size - The file size in bytes.
|
||||
* - duration - The length in seconds of the audio media.
|
||||
* - width - The width in pixels of the audio media.
|
||||
* - height - The height in pixels of the audio media.
|
||||
* - tempInfo - mediaInfo (with the same properties as this except no tempInfo) for a temporary image while the file downloads.
|
||||
*/
|
||||
required property var mediaInfo
|
||||
|
||||
/**
|
||||
* @brief Whether the media has been downloaded.
|
||||
*/
|
||||
readonly property bool downloaded: root.progressInfo && root.progressInfo.completed
|
||||
|
||||
/**
|
||||
* @brief Whether the video should be played when downloaded.
|
||||
*/
|
||||
property bool playOnFinished: false
|
||||
|
||||
/**
|
||||
* @brief The maximum width of the image.
|
||||
*/
|
||||
readonly property var maxWidth: Kirigami.Units.gridUnit * 30
|
||||
|
||||
/**
|
||||
* @brief The maximum height of the image.
|
||||
*/
|
||||
readonly property var maxHeight: Kirigami.Units.gridUnit * 30
|
||||
|
||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||
|
||||
onDownloadedChanged: {
|
||||
if (downloaded) {
|
||||
vid.source = root.progressInfo.localPath
|
||||
}
|
||||
|
||||
if (downloaded && playOnFinished) {
|
||||
playSavedFile()
|
||||
playOnFinished = false
|
||||
}
|
||||
}
|
||||
|
||||
bubbleContent: Video {
|
||||
id: vid
|
||||
implicitWidth: mediaSizeHelper.currentSize.width
|
||||
implicitHeight: mediaSizeHelper.currentSize.height
|
||||
|
||||
fillMode: VideoOutput.PreserveAspectFit
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "notDownloaded"
|
||||
when: !root.progressInfo.completed && !root.progressInfo.active
|
||||
PropertyChanges {
|
||||
target: noDownloadLabel
|
||||
visible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
target: mediaThumbnail
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "downloading"
|
||||
when: root.progressInfo.active && !root.progressInfo.completed
|
||||
PropertyChanges {
|
||||
target: downloadBar
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "paused"
|
||||
when: root.progressInfo.completed && (vid.playbackState === MediaPlayer.StoppedState || vid.playbackState === MediaPlayer.PausedState)
|
||||
PropertyChanges {
|
||||
target: videoControls
|
||||
stateVisible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
target: playButton
|
||||
icon.name: "media-playback-start"
|
||||
onClicked: vid.play()
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "playing"
|
||||
when: root.progressInfo.completed && vid.playbackState === MediaPlayer.PlayingState
|
||||
PropertyChanges {
|
||||
target: videoControls
|
||||
stateVisible: true
|
||||
}
|
||||
PropertyChanges {
|
||||
target: playButton
|
||||
icon.name: "media-playback-pause"
|
||||
onClicked: vid.pause()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Image {
|
||||
id: mediaThumbnail
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
|
||||
source: root.mediaInfo.tempInfo.source
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
id: noDownloadLabel
|
||||
anchors.centerIn: parent
|
||||
|
||||
visible: false
|
||||
color: "white"
|
||||
text: i18n("Video")
|
||||
font.pixelSize: 16
|
||||
|
||||
padding: 8
|
||||
|
||||
background: Rectangle {
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
color: "black"
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: downloadBar
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
radius: Kirigami.Units.smallSpacing
|
||||
|
||||
QQC2.ProgressBar {
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: parent.width * 0.8
|
||||
|
||||
from: 0
|
||||
to: root.progressInfo.total
|
||||
value: root.progressInfo.progress
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Control {
|
||||
id: videoControls
|
||||
property bool stateVisible: false
|
||||
|
||||
anchors.bottom: vid.bottom
|
||||
anchors.left: vid.left
|
||||
anchors.right: vid.right
|
||||
visible: stateVisible && (videoHoverHandler.hovered || volumePopupHoverHandler.hovered || volumeSlider.hovered || videoControlTimer.running)
|
||||
|
||||
contentItem: RowLayout {
|
||||
id: controlRow
|
||||
QQC2.ToolButton {
|
||||
id: playButton
|
||||
}
|
||||
QQC2.Slider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: vid.duration
|
||||
value: vid.position
|
||||
onMoved: vid.seek(value)
|
||||
}
|
||||
QQC2.Label {
|
||||
text: Controller.formatDuration(vid.position) + "/" + Controller.formatDuration(vid.duration)
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: volumeButton
|
||||
property var unmuteVolume: vid.volume
|
||||
|
||||
icon.name: vid.volume <= 0 ? "player-volume-muted" : "player-volume"
|
||||
|
||||
QQC2.ToolTip.visible: hovered
|
||||
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.timeout: Kirigami.Units.toolTipDelay
|
||||
QQC2.ToolTip.text: i18nc("@action:button", "Volume")
|
||||
|
||||
onClicked: {
|
||||
if (vid.volume > 0) {
|
||||
vid.volume = 0
|
||||
} else {
|
||||
if (unmuteVolume === 0) {
|
||||
vid.volume = 1
|
||||
} else {
|
||||
vid.volume = unmuteVolume
|
||||
}
|
||||
}
|
||||
}
|
||||
onHoveredChanged: {
|
||||
if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
|
||||
videoControlTimer.restart()
|
||||
volumePopupTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.Popup {
|
||||
id: volumePopup
|
||||
y: -height
|
||||
width: volumeButton.width
|
||||
visible: videoControls.stateVisible && (volumeButton.hovered || volumePopupHoverHandler.hovered || volumeSlider.hovered || volumePopupTimer.running)
|
||||
|
||||
focus: true
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
closePolicy: QQC2.Popup.NoAutoClose
|
||||
|
||||
QQC2.Slider {
|
||||
id: volumeSlider
|
||||
anchors.centerIn: parent
|
||||
implicitHeight: Kirigami.Units.gridUnit * 7
|
||||
orientation: Qt.Vertical
|
||||
padding: 0
|
||||
from: 0
|
||||
to: 1
|
||||
value: vid.volume
|
||||
onMoved: {
|
||||
vid.volume = value
|
||||
volumeButton.unmuteVolume = value
|
||||
}
|
||||
onHoveredChanged: {
|
||||
if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
|
||||
videoControlTimer.restart()
|
||||
volumePopupTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: volumePopupTimer
|
||||
interval: 500
|
||||
}
|
||||
HoverHandler {
|
||||
id: volumePopupHoverHandler
|
||||
onHoveredChanged: {
|
||||
if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
|
||||
videoControlTimer.restart()
|
||||
volumePopupTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
background: Kirigami.ShadowedRectangle {
|
||||
radius: 4
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
opacity: 0.8
|
||||
|
||||
property color borderColor: Kirigami.Theme.textColor
|
||||
border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
|
||||
border.width: 1
|
||||
|
||||
shadow.xOffset: 0
|
||||
shadow.yOffset: 4
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.3)
|
||||
shadow.size: 8
|
||||
}
|
||||
}
|
||||
}
|
||||
QQC2.ToolButton {
|
||||
id: maximizeButton
|
||||
display: QQC2.AbstractButton.IconOnly
|
||||
|
||||
action: Kirigami.Action {
|
||||
text: i18n("Maximize")
|
||||
icon.name: "view-fullscreen"
|
||||
onTriggered: {
|
||||
root.ListView.view.interactive = false
|
||||
vid.pause()
|
||||
// We need to make sure the index is that of the MediaMessageFilterModel.
|
||||
if (root.ListView.view.model instanceof MessageFilterModel) {
|
||||
RoomManager.maximizeMedia(RoomManager.mediaMessageFilterModel.getRowForSourceItem(root.index))
|
||||
} else {
|
||||
RoomManager.maximizeMedia(root.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
background: Kirigami.ShadowedRectangle {
|
||||
radius: 4
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
opacity: 0.8
|
||||
|
||||
property color borderColor: Kirigami.Theme.textColor
|
||||
border.color: Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0.3)
|
||||
border.width: 1
|
||||
|
||||
shadow.xOffset: 0
|
||||
shadow.yOffset: 4
|
||||
shadow.color: Qt.rgba(0, 0, 0, 0.3)
|
||||
shadow.size: 8
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: videoControlTimer
|
||||
interval: 1000
|
||||
}
|
||||
HoverHandler {
|
||||
id: videoHoverHandler
|
||||
onHoveredChanged: {
|
||||
if (!hovered && (vid.state === "paused" || vid.state === "playing")) {
|
||||
videoControlTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds | TapHandler.WithinBounds
|
||||
onTapped: if (root.progressInfo.completed) {
|
||||
if (vid.playbackState == MediaPlayer.PlayingState) {
|
||||
vid.pause()
|
||||
} else {
|
||||
vid.play()
|
||||
}
|
||||
} else {
|
||||
root.downloadAndPlay()
|
||||
}
|
||||
}
|
||||
|
||||
MediaSizeHelper {
|
||||
id: mediaSizeHelper
|
||||
contentMaxWidth: root.contentMaxWidth
|
||||
mediaWidth: root.mediaInfo.width
|
||||
mediaHeight: root.mediaInfo.height
|
||||
}
|
||||
}
|
||||
|
||||
function downloadAndPlay() {
|
||||
if (vid.downloaded) {
|
||||
playSavedFile()
|
||||
} else {
|
||||
playOnFinished = true
|
||||
ListView.view.currentRoom.downloadFile(root.eventId, Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/" + root.eventId.replace(":", "_").replace("/", "_").replace("+", "_") + ListView.view.currentRoom.fileNameToDownload(root.eventId))
|
||||
}
|
||||
}
|
||||
|
||||
function playSavedFile() {
|
||||
vid.stop()
|
||||
vid.play()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user