Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
22 KB
Referenced Files
None
Subscribers
None
diff --git a/src/contents/ui/KazvIOMenu.qml b/src/contents/ui/KazvIOMenu.qml
index be41d36..60e8259 100644
--- a/src/contents/ui/KazvIOMenu.qml
+++ b/src/contents/ui/KazvIOMenu.qml
@@ -1,142 +1,142 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2023 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.kirigami 2.13 as Kirigami
import moe.kazv.mxc.kazv 0.0 as MK
ColumnLayout {
id: kazvIOProgressBar
required property var kazvIOJob
- property var jobId
- property bool isUpload
+ required property var jobId
+ required property bool isUpload
visible: kazvIOJob ? true : false
onKazvIOJobChanged: {
if (kazvIOJob == null) {
progressBarLayout.visible = true
resultMsgLayout.visible = false
return
}
if (kazvIOJob.isResulted()) {
jobSlots.onResult(kazvIOJob.error())
return
}
if (kazvIOJob.isSuspended()) {
pauseAction.suspended = true
}
}
Connections {
id: jobSlots
target: kazvIOJob
function onResult(ec) {
progressBarLayout.visible = false
resultMsgLayout.visible = true
if (ec == MK.KazvIOBaseJob.NoError) {
if (isUpload) {
return
}
resultMsg.text = l10n.get('kazv-io-download-success-prompt')
return
}
let resultL10nId = isUpload ? 'kazv-io-upload-failure-prompt' : 'kazv-io-download-failure-prompt'
let detailL10nId = new Map([
[MK.KazvIOBaseJob.UserCancel, 'kazv-io-failure-detail-user-cancel'],
[MK.KazvIOBaseJob.OpenFileError, 'kazv-io-failure-detail-open-file-error'],
[MK.KazvIOBaseJob.WriteFileError, 'kazv-io-failure-detail-write-file-error'],
[MK.KazvIOBaseJob.KIOError, 'kazv-io-failure-detail-network-error'],
[MK.KazvIOBaseJob.HashError, 'kazv-io-failure-detail-hash-error'],
[MK.KazvIOBaseJob.KazvError, 'kazv-io-failure-detail-kazv-error']
])
resultMsg.text = l10n.get(resultL10nId, {detail: l10n.get(detailL10nId.get(ec))})
}
}
Label {
property string l10nId: isUpload ? 'kazv-io-uploading-prompt' : 'kazv-io-downloading-prompt'
text: kazvIOJob ? l10n.get(l10nId, {fileName: kazvIOJob.fileName()}) : ""
wrapMode: Text.Wrap
Layout.preferredWidth: parent.width
}
RowLayout {
id: progressBarLayout
visible: true
Layout.preferredWidth: parent.width
ProgressBar {
id: progressBar
Layout.fillWidth: true
value: kazvIOJob ? kazvIOJob.progress : 0
}
Kirigami.Action {
id: pauseAction
text: suspended ? l10n.get("kazv-io-resume") : l10n.get("kazv-io-pause")
iconName: suspended ? "media-playback-start" : "media-playback-pause"
property var suspended: false
onTriggered: {
if (pauseAction.suspended) {
kazvIOJob.resume()
} else {
kazvIOJob.suspend()
}
suspended = !suspended
}
}
Kirigami.Action {
id: cancelAction
text: l10n.get("kazv-io-cancel")
iconName: "dialog-cancel"
onTriggered: {
pauseAction.suspended = false
kazvIOJob.cancel()
}
}
RoundButton {
id: pauseBtn
Accessible.name: pauseAction.suspended ? l10n.get('kazv-io-resume') : l10n.get('kazv-io-pause')
icon.name: pauseAction.suspended ? "media-playback-start" : "media-playback-pause"
onClicked: pauseAction.trigger()
}
RoundButton {
icon.name: "dialog-cancel"
Accessible.name: l10n.get('kazv-io-cancel')
onClicked: cancelAction.trigger()
}
}
ColumnLayout {
id: resultMsgLayout
visible: false
width: parent.width
Label {
id: resultMsg
wrapMode: Text.Wrap
Layout.preferredWidth: parent.width
}
Button {
text: l10n.get('kazv-io-prompt-close')
onClicked: {
if (isUpload) {
kazvIOManager.deleteUploadJob(jobId, kazvIOJob)
} else {
kazvIOManager.deleteDownloadJob(jobId)
resultMsgLayout.visible = false
progressBarLayout.visible = true
resultMsg.text = null
kazvIOJob = null
}
}
}
}
}
diff --git a/src/contents/ui/MediaFileMenu.qml b/src/contents/ui/MediaFileMenu.qml
index 72b6190..1a1b382 100644
--- a/src/contents/ui/MediaFileMenu.qml
+++ b/src/contents/ui/MediaFileMenu.qml
@@ -1,54 +1,59 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2023 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Dialogs 1.3
import Qt.labs.platform 1.1 as Platform
import org.kde.kirigami 2.13 as Kirigami
import '.' as Types
QtObject {
id: mediaFileMenu
- required property var serverUrl
- required property var jobId
- required property var fileName
- required property var hash
- /**
- * key and iv for encryption. If encryption is not enabled, the value is ""
- **/
- required property var key
- required property var iv
+ required property var eventContent
+
+ property var jobManager: kazvIOManager
+ property var mtxSdk: matrixSdk
signal startDownload
+ property var fileHandler: FileHandler {
+ id: fileHandler
+ autoCache: false
+ eventContent: mediaFileMenu.eventContent
+ kazvIOManager: mediaFileMenu.jobManager
+ matrixSdk: mediaFileMenu.mtxSdk
+ }
+
property var viewAction: Kirigami.Action {
text: l10n.get('media-file-menu-option-view')
// TODO: open with default program
}
property var saveAction: Kirigami.Action {
text: l10n.get('media-file-menu-option-save-as')
onTriggered: {
fileDialog.open()
}
}
property var optionMenu: [viewAction, saveAction]
property var fileDialog: FileDialog {
folder: Platform.StandardPaths.writableLocation(Platform.StandardPaths.DownloadLocation)
selectExisting: false
onAccepted: {
- kazvIOManager.startNewDownloadJob(mediaFileMenu.serverUrl, fileUrl, mediaFileMenu.jobId,
- mediaFileMenu.hash, mediaFileMenu.key, mediaFileMenu.iv)
- startDownload()
+ mediaFileMenu.fileHandler.downloadFile(fileUrl)
}
}
+
+ Component.onCompleted: {
+ mediaFileMenu.fileHandler.startDownload.connect(mediaFileMenu.startDownload)
+ }
}
diff --git a/src/contents/ui/event-types/Audio.qml b/src/contents/ui/event-types/Audio.qml
index 95669bc..478b293 100644
--- a/src/contents/ui/event-types/Audio.qml
+++ b/src/contents/ui/event-types/Audio.qml
@@ -1,70 +1,68 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import moe.kazv.mxc.kazv 0.0 as MK
import QtMultimedia 5.15
import org.kde.kirigami 2.13 as Kirigami
import '.' as Types
import '..' as Kazv
Simple {
id: upper
property var gender: 'neutral'
property var body: event.content.body
property var mxcUri: event.content.url
property var audioUri: matrixSdk.mxcUriToHttp(mxcUri)
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
Types.MediaBubble {
id: bubble
- Layout.fillWidth: true
- eventId: event.eventId
- serverUrl: upper.audioUri
- fileName: body
+ eventContent: event.content
+ mediaId: mxcUri.toString().split('/').slice(-1)[0]
ColumnLayout {
property var msgLabel: Kazv.SelectableText {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: l10n.get('event-message-audio-sent', { gender, body })
}
property var audio: Audio {
id: audio
source: audioUri
autoLoad: false
autoPlay: false
}
property var playLabel: Label {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: l10n.get('event-message-audio-play-audio')
TapHandler {
onSingleTapped: {
audio.play()
}
}
}
data: [
msgLabel,
audio,
playLabel,
bubble.mediaFileMenu,
bubble.progressBar
]
}
}
}
diff --git a/src/contents/ui/event-types/File.qml b/src/contents/ui/event-types/File.qml
index 4665346..7982816 100644
--- a/src/contents/ui/event-types/File.qml
+++ b/src/contents/ui/event-types/File.qml
@@ -1,56 +1,54 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.2
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import moe.kazv.mxc.kazv 0.0 as MK
import org.kde.kirigami 2.13 as Kirigami
import '.' as Types
import '..' as Kazv
Simple {
id: upper
property var gender: 'neutral'
property var body: event.content.body
property var mxcUri: event.content.url
property var fileUri: matrixSdk.mxcUriToHttp(mxcUri)
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
Types.MediaBubble {
id: bubble
- Layout.fillWidth: true
- eventId: event.eventId
- serverUrl: upper.fileUri
- fileName: body
+ eventContent: event.content
+ mediaId: mxcUri.toString().split('/').slice(-1)[0]
ColumnLayout {
Layout.fillWidth: true
property var msgLabel: Kazv.SelectableText {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: l10n.get('event-message-file-sent', { gender, body })
}
property var uriLabel: Label {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: fileUri
}
data: [
msgLabel,
uriLabel,
bubble.mediaFileMenu,
bubble.progressBar
]
}
}
}
diff --git a/src/contents/ui/event-types/Image.qml b/src/contents/ui/event-types/Image.qml
index 132c7a7..68167f9 100644
--- a/src/contents/ui/event-types/Image.qml
+++ b/src/contents/ui/event-types/Image.qml
@@ -1,104 +1,95 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import moe.kazv.mxc.kazv 0.0 as MK
import org.kde.kirigami 2.13 as Kirigami
import '.' as Types
import '..' as Kazv
Simple {
id: upper
property var gender: 'neutral'
property var body: event.content.body
property var thumbnailFile: imageInfo.thumbnail_file || {}
property var thumbnailInfo: imageInfo.thumbnail_info || {}
- property var thumbnailMxcUri: thumbnailFile.url || imageInfo.thumbnail_url || ""
- property var thumbnailSha256: thumbnailFile.hashes ? thumbnailFile.hashes.sha256 : ""
- property var thumbnailKey: thumbnailFile.key ? thumbnailFile.key.k : ""
- property var thumbnailIv: thumbnailFile.iv || ""
- property var thumbnailUri: thumbnailMxcUri ? kazvIOManager.cacheFile(matrixSdk.mxcUriToHttp(thumbnailMxcUri), thumbnailMxcUri.split('/')[3], thumbnailSha256, thumbnailKey, thumbnailIv) : ""
property var thumbnailWidth: thumbnailInfo.w
property var thumbnailHeight: thumbnailInfo.h
property var imageInfo: event.content.info || {}
property var imageFile: event.content.file || {}
- property var imageMxcUri: imageFile.url || event.content.url
- property var imageSha256: imageFile.hashes ? imageFile.hashes.sha256 : ""
- property var imageKey: imageFile.key ? imageFile.key.k : ""
- property var imageIv: imageFile.iv || ""
- property var imageUri: thumbnailMxcUri ? matrixSdk.mxcUriToHttp(imageMxcUri) : kazvIOManager.cacheFile(matrixSdk.mxcUriToHttp(imageMxcUri), imageMxcUri.split('/')[3], imageSha256, imageKey, imageIv) // If there are no thumbnail, cache the image
property var imageWidth: imageInfo.w
property var imageHeight: imageInfo.h
- property var previewUri: thumbnailMxcUri ? thumbnailUri : imageUri // Uri for source of Image QML type
- property var mediaId: previewUri.toString().split('/').slice(-1)[0]
+ property var imageMxcUri: fileHandler.encryptedFileMxcUri || fileHandler.unencryptedFileMxcUri
+ property var mediaId: imageMxcUri.toString().split('/').slice(-1)[0]
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
- property var kazvIOJob
+ property var jobManager: kazvIOManager
+ property var mtxSdk: matrixSdk
+
+ Kazv.FileHandler {
+ id: fileHandler
+ eventContent: event.content
+ autoCache: true
+ kazvIOManager: upper.jobManager
+ matrixSdk: upper.mtxSdk
+ }
Types.MediaBubble {
id: bubble
- eventId: event.eventId
- serverUrl: upper.imageUri
- fileName: body
- hash: imageSha256
- key: upper.imageKey
- iv: upper.imageIv
+ eventContent: event.content
+ mediaId: upper.mediaId
property var label: Kazv.SelectableText {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: l10n.get('event-message-image-sent', { gender, body })
}
property var image: Image {
id: image
- source: kazvIOJob ? "" : previewUri
- Layout.preferredWidth: calcImageWidth()
- Layout.maximumWidth: innerContentWidth
- Layout.preferredHeight: calcImageHeight()
+
+ source: fileHandler.success ? fileHandler.cachedFile : ""
+ width: calcImageWidth() > innerContentWidth ? innerContentWidth : calcImageWidth()
+ height: calcImageHeight()
fillMode: Image.PreserveAspectFit
}
ColumnLayout {
id: layout
Layout.fillWidth: true
data: [
bubble.mediaFileMenu,
bubble.label,
bubble.image,
bubble.progressBar
]
}
}
function calcImageWidth() {
- const eventSpecWidth = thumbnailMxcUri ? thumbnailWidth : imageWidth
+ const eventSpecWidth = thumbnailWidth || imageWidth
return eventSpecWidth || image.implicitWidth || 1
}
function calcImageHeight() {
- const eventSpecHeight = thumbnailMxcUri ? thumbnailHeight : imageHeight
+ const eventSpecHeight = thumbnailHeight || imageHeight
const height = eventSpecHeight || image.implicitHeight || 1
const width = calcImageWidth()
if (width > innerContentWidth) {
return height * (innerContentWidth / width)
}
return height
}
-
- Component.onCompleted: {
- upper.kazvIOJob = kazvIOManager.getDownloadJob(mediaId)
- }
}
diff --git a/src/contents/ui/event-types/MediaBubble.qml b/src/contents/ui/event-types/MediaBubble.qml
index 26bbec5..79f298f 100644
--- a/src/contents/ui/event-types/MediaBubble.qml
+++ b/src/contents/ui/event-types/MediaBubble.qml
@@ -1,48 +1,37 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2023 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import moe.kazv.mxc.kazv 0.0 as MK
import '..' as Kazv
Kazv.Bubble {
id: bubble
- required property var eventId
- required property var serverUrl
- required property var fileName
- required property var hash
- required property var key
- required property var iv
+ required property var eventContent
+ required property var mediaId
property var mediaFileMenu: Kazv.MediaFileMenu {
- Layout.fillWidth: true
- serverUrl: bubble.serverUrl
- jobId: bubble.eventId
- fileName: bubble.fileName
- hash: bubble.hash
- key: bubble.key
- iv: bubble.iv
+ eventContent: bubble.eventContent
onStartDownload: {
- progressBar.kazvIOJob = kazvIOManager.getDownloadJob(eventId)
+ progressBar.kazvIOJob = kazvIOManager.getDownloadJob(bubble.mediaId)
}
}
menuContent: mediaFileMenu.optionMenu
property var progressBar: Kazv.KazvIOMenu {
id: progressBar
- Layout.fillWidth: true
- jobId: upper.mediaId
+ kazvIOJob: null
+ jobId: bubble.mediaId
isUpload: false
- kazvIOJob: upper.kazvIOJob
width: parent.width
}
}
diff --git a/src/contents/ui/event-types/Video.qml b/src/contents/ui/event-types/Video.qml
index 00c725e..da53d0e 100644
--- a/src/contents/ui/event-types/Video.qml
+++ b/src/contents/ui/event-types/Video.qml
@@ -1,118 +1,117 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import moe.kazv.mxc.kazv 0.0 as MK
import QtMultimedia 5.15
import org.kde.kirigami 2.13 as Kirigami
import '.' as Types
import '..' as Kazv
Simple {
id: upper
property var gender: 'neutral'
property var body: event.content.body
property var mxcUri: event.content.url
property var videoUri: matrixSdk.mxcUriToHttp(mxcUri)
property var videoInfo: event.content.info || {}
property var videoResolution: video.metaData.resolution
property var videoWidth: videoResolution && videoResolution.width || (videoInfo.w || 1)
property var videoHeight: videoResolution && videoResolution.height || (videoInfo.h || 1)
property var thumbnailInfo: videoInfo.thumbnail_info || {}
property var thumbnailMxcUri: videoInfo.thumbnail_url
property var thumbnailUri: matrixSdk.mxcUriToHttp(thumbnailMxcUri)
property var hasThumbnail: !! thumbnailMxcUri
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
Types.MediaBubble {
id: bubble
Layout.fillWidth: true
- eventId: event.eventId
- serverUrl: upper.videoUri
- fileName: body
+ eventContent: event.content
+ mediaId: mxcUri.toString().split('/').slice(-1)[0]
ColumnLayout {
id: layout
property var label: Kazv.SelectableText {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: l10n.get('event-message-video-sent', { gender, body })
}
property var video: Video {
id: video
source: videoUri
autoLoad: false
autoPlay: false
loops: MediaPlayer.Infinite
Layout.minimumHeight: Kirigami.Units.gridUnit * 10
Layout.minimumWidth: Kirigami.Units.gridUnit * 10
Layout.maximumWidth: innerContentWidth
Layout.preferredWidth: videoWidth
Layout.preferredHeight: videoHeight / videoWidth * width
fillMode: VideoOutput.PreserveAspectFit
TapHandler {
onSingleTapped: {
video.playOrPause();
}
}
Image {
anchors.fill: parent
source: thumbnailUri
visible: video.playbackState == MediaPlayer.StoppedState && hasThumbnail
fillMode: Image.PreserveAspectFit
data: [bubble.mediaFileMenu]
}
Rectangle {
anchors.fill: parent
color: Kirigami.Theme.negativeBackgroundColor //Kirigami.ColorUtils.tintWithAlpha(color, Kirigami.Theme.textColor, 0.15)
visible: {
video.playbackState == MediaPlayer.StoppedState &&
! hasThumbnail
}
}
onStatusChanged: {
console.log('status = ', video.status);
}
onPlaybackStateChanged: {
console.log('playback state = ', video.playbackState);
}
function playOrPause() {
console.log('playback state ==', video.playbackState);
if (video.playbackState == MediaPlayer.PlayingState) {
video.pause();
} else {
if (video.playbackState == MediaPlayer.StoppedState) {
video.seek(0);
}
video.play();
}
}
}
data: [
label,
video,
bubble.progressBar
]
}
}
}
diff --git a/src/kazv-io-manager.hpp b/src/kazv-io-manager.hpp
index 499db71..581463a 100644
--- a/src/kazv-io-manager.hpp
+++ b/src/kazv-io-manager.hpp
@@ -1,63 +1,64 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022-2023 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include "kazv-io-job.hpp"
#include "matrix-room.hpp"
#include "upload-job-model.hpp"
#include "matrix-room-list.hpp"
#include "matrix-sdk.hpp"
#include <QObject>
#include <QtQml>
#include <QUrl>
#include <QString>
#include <KIO/TransferJob>
#include <QPointer>
#include <memory>
struct KazvIOManagerPrivate;
class KazvIOManager : public QObject
{
Q_OBJECT
QML_ELEMENT
std::unique_ptr<KazvIOManagerPrivate> m_d;
Q_PROPERTY(QString cacheDirectory READ cacheDirectory WRITE setCacheDirectory NOTIFY cacheDirectoryChanged)
public:
explicit KazvIOManager(QObject *parent = 0);
~KazvIOManager() override;
/**
* Cache the file specified by fileUrl into a temporary folder
+ * Multiple calls do not repeat downloads
* Returns the local url of the cached file.
*/
Q_INVOKABLE QUrl cacheFile(const QUrl &fileUrl, const QString &id, const QString &hash = QStringLiteral(""),
const QString &key = QStringLiteral(""), const QString &iv = QStringLiteral(""));
Q_INVOKABLE KazvIOBaseJob *startNewDownloadJob(const QUrl &serverUrl, const QUrl &localFileName,
const QString &jobId, const QString &hash,
const QString &key = QStringLiteral(""), const QString &iv = QStringLiteral(""));
Q_INVOKABLE KazvIOBaseJob *startNewUploadJob(const QUrl &serverUrl, const QUrl &localFileName,
const QString &token, const QString &roomId, MatrixRoomList *roomList, const bool encrypted);
Q_INVOKABLE KazvIOBaseJob *startNewRoomlessUploadJob(const QUrl &serverUrl, const QUrl &localFileName, const QString &token);
Q_INVOKABLE KazvIOBaseJob *getDownloadJob(const QString &jobId);
Q_INVOKABLE void deleteDownloadJob(const QString &jobId);
Q_INVOKABLE UploadJobModel *getUploadJobs(const QString &roomId);
Q_INVOKABLE void deleteUploadJob(const QString &roomId, KazvIOBaseJob *job);
Q_INVOKABLE void deleteRoomlessUploadJob(KazvIOBaseJob *job);
Q_INVOKABLE void deleteModelIfEmpty(const QString &roomId);
Q_INVOKABLE void clearJobs();
QString cacheDirectory() const;
void setCacheDirectory(QString cacheDirectory);
Q_SIGNALS:
void cacheDirectoryChanged();
};

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 2, 9:38 AM (4 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1804254
Default Alt Text
(22 KB)

Event Timeline