// SPDX-FileCopyrightText: 2022 Tobias Fella // SPDX-FileCopyrightText: 2024 James Graham // SPDX-License-Identifier: GPL-2.0-or-later import QtQuick import QtQuick.Controls as QQC2 import QtQuick.Layouts import QtMultimedia import org.kde.coreaddons import org.kde.kirigami as Kirigami import org.kde.neochat /** * @brief A component to show audio from a message. */ ColumnLayout { id: root /** * @brief The NeoChatRoom the delegate is being displayed in. */ required property NeoChatRoom room /** * @brief The matrix ID of the message event. */ required property string eventId /** * @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 image/xxx for this delegate). * - mimeIcon - The MIME icon name (should be image-xxx). * - size - The file size in bytes. * - 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. * - filename - original filename of the media */ required property var mediaInfo /** * @brief FileTransferInfo for any downloading files. */ required property var fileTransferInfo /** * @brief Whether the media has been downloaded. */ readonly property bool downloaded: root.fileTransferInfo && root.fileTransferInfo.completed onDownloadedChanged: if (downloaded) { audio.play(); } /** * @brief The maximum width that the bubble's content can be. */ property real maxContentWidth: -1 MediaPlayer { id: audio onErrorOccurred: (error, errorString) => console.warn("Audio playback error:" + error + errorString) audioOutput: AudioOutput {} } states: [ State { name: "notDownloaded" when: !root.fileTransferInfo.completed && !root.fileTransferInfo.active PropertyChanges { target: playButton icon.name: "media-playback-start" onClicked: root.room.downloadFile(root.eventId) } }, State { name: "downloading" when: root.fileTransferInfo.active && !root.fileTransferInfo.completed PropertyChanges { target: downloadBar visible: true } PropertyChanges { target: playButton icon.name: "media-playback-stop" onClicked: { root.room.cancelFileTransfer(root.eventId); } } }, State { name: "paused" when: root.fileTransferInfo.completed && (audio.playbackState === MediaPlayer.StoppedState || audio.playbackState === MediaPlayer.PausedState) PropertyChanges { target: playButton icon.name: "media-playback-start" onClicked: { audio.source = root.fileTransferInfo.localPath; MediaManager.startPlayback(); audio.play(); } } }, State { name: "playing" when: root.fileTransferInfo.completed && audio.playbackState === MediaPlayer.PlayingState PropertyChanges { target: playButton icon.name: "media-playback-pause" onClicked: audio.pause() } } ] Connections { target: MediaManager function onPlaybackStarted() { if (audio.playbackState === MediaPlayer.PlayingState) { audio.pause(); } } } RowLayout { spacing: Kirigami.Units.smallSpacing QQC2.ToolButton { id: playButton } ColumnLayout { spacing: 0 QQC2.Label { text: root.mediaInfo.filename wrapMode: Text.Wrap Layout.fillWidth: true } QQC2.Label { text: Format.formatDuration(root.mediaInfo.duration) color: Kirigami.Theme.disabledTextColor visible: !audio.hasAudio Layout.fillWidth: true } } } QQC2.ProgressBar { id: downloadBar visible: false Layout.fillWidth: true from: 0 to: root.mediaInfo.size value: root.fileTransferInfo.progress } RowLayout { visible: audio.hasAudio QQC2.Slider { Layout.fillWidth: true from: 0 to: audio.duration value: audio.position onMoved: audio.setPosition(value) } QQC2.Label { visible: root.maxContentWidth > Kirigami.Units.gridUnit * 12 text: Format.formatDuration(audio.position) + "/" + Format.formatDuration(audio.duration) } } QQC2.Label { Layout.alignment: Qt.AlignRight Layout.rightMargin: Kirigami.Units.smallSpacing visible: audio.hasAudio && root.maxContentWidth < Kirigami.Units.gridUnit * 12 text: Format.formatDuration(audio.position) + "/" + Format.formatDuration(audio.duration) } }