Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140436
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/contents/ui/KazvIOMenu.qml b/src/contents/ui/KazvIOMenu.qml
index 48e678f..5538758 100644
--- a/src/contents/ui/KazvIOMenu.qml
+++ b/src/contents/ui/KazvIOMenu.qml
@@ -1,121 +1,130 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022 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
visible: kazvIOJob ? true : false
onKazvIOJobChanged: {
if (kazvIOJob == null) {
return
}
+ if (kazvIOJob.isResulted()) {
+ if (kazvIOJob.error()) {
+ jobSlots.onFailure()
+ } else {
+ jobSlots.onSuccess()
+ }
+ return
+ }
if (kazvIOJob.isSuspended()) {
pauseAction.suspended = true
}
}
Connections {
+ id: jobSlots
target: kazvIOJob
function onSuccess() {
// Successful upload job don't need prompt
if (isUpload) {
return
}
progressBarLayout.visible = false
promptMsgLayout.visible = true
promptMsg.text = l10n.get('kazv-io-download-success-prompt')
}
function onFailure() {
progressBarLayout.visible = false
promptMsgLayout.visible = true
if (isUpload) {
promptMsg.text = l10n.get('kazv-io-upload-failure-prompt')
} else {
promptMsg.text = l10n.get('kazv-io-download-failure-prompt')
}
}
}
Label {
text: kazvIOJob ? kazvIOJob.fileName() : ''
}
RowLayout {
id: progressBarLayout
visible: true
Layout.preferredWidth: parent.width
ProgressBar {
id: progressBar
Layout.fillWidth: true
value: kazvIOJob ? kazvIOJob.progress : 0
}
Kirigami.Action {
id: pauseAction
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
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()
}
}
RowLayout {
id: promptMsgLayout
visible: false
Text {
id: promptMsg
}
Button {
text: l10n.get('kazv-io-prompt-close')
onClicked: {
if (isUpload) {
kazvIOManager.deleteUploadJob(jobId, kazvIOJob)
} else {
kazvIOManager.deleteDownloadJob(jobId)
+ promptMsgLayout.visible = false
+ progressBarLayout.visible = true
+ kazvIOJob = null
}
- promptMsgLayout.visible = false
- progressBarLayout.visible = true
- kazvIOJob = null
}
}
}
}
diff --git a/src/kazv-io-job.cpp b/src/kazv-io-job.cpp
index 4aa7371..d9da263 100644
--- a/src/kazv-io-job.cpp
+++ b/src/kazv-io-job.cpp
@@ -1,224 +1,233 @@
#include "kazv-io-job.hpp"
#include "matrix-room.hpp"
#include <QObject>
#include <QPointer>
#include <QSharedPointer>
#include <QSaveFile>
#include <QFile>
#include <QByteArray>
#include <QIODevice>
#include <QString>
#include <KJob>
#include <KIO/TransferJob>
#include <nlohmann/json.hpp>
#include <optional>
#include <string>
using json = nlohmann::json;
struct KazvIOBaseJobPrivate
{
QPointer<KIO::TransferJob> job;
std::optional<bool> result = std::nullopt;
};
KazvIOBaseJob::KazvIOBaseJob(QObject *parent)
: QObject(parent)
, m_d(new KazvIOBaseJobPrivate)
{
connect(this, &KazvIOBaseJob::jobChanged, this, &KazvIOBaseJob::connectJob);
}
KazvIOBaseJob::~KazvIOBaseJob() = default;
QPointer<KIO::TransferJob> KazvIOBaseJob::job()
{
return m_d->job;
}
void KazvIOBaseJob::setJob(QPointer<KIO::TransferJob> job)
{
m_d->job = job;
Q_EMIT jobChanged();
}
float KazvIOBaseJob::progress() {
if (m_d->job.isNull()) {
return 0;
}
return static_cast<float>(m_d->job->percent()) / 100;
}
void KazvIOBaseJob::suspend()
{
m_d->job->suspend();
}
void KazvIOBaseJob::resume()
{
m_d->job->resume();
}
void KazvIOBaseJob::cancel()
{
m_d->job->kill(KJob::EmitResult);
}
bool KazvIOBaseJob::isSuspended()
{
return m_d->job->isSuspended();
}
bool KazvIOBaseJob::isResulted()
{
return m_d->result.has_value();
}
+bool KazvIOBaseJob::error()
+{
+ if (m_d->result.has_value()) {
+ return !m_d->result.value();
+ }
+ // Shouldn't call this function before result are emited
+ return false;
+}
+
void KazvIOBaseJob::connectJob()
{
connect(m_d->job, &KJob::result, this, [this](KJob *job) {
Q_EMIT result();
if (job->error()) {
m_d->result = false;
Q_EMIT failure();
} else {
m_d->result = true;
Q_EMIT success();
}
});
connect(m_d->job, &KJob::percentChanged, this, &KazvIOBaseJob::emitProgressChanged);
}
void KazvIOBaseJob::emitProgressChanged(KJob * /* job */, unsigned long /* percent */) {
Q_EMIT progressChanged();
}
struct KazvIODownloadJobPrivate
{
QSharedPointer<QSaveFile> file;
};
KazvIODownloadJob::KazvIODownloadJob(QObject *parent)
: KazvIOBaseJob(parent)
, m_d(new KazvIODownloadJobPrivate)
{
}
KazvIODownloadJob::~KazvIODownloadJob() = default;
QPointer<QSaveFile> KazvIODownloadJob::file()
{
return m_d->file.data();
}
void KazvIODownloadJob::setFile(QPointer<QSaveFile> file)
{
if (!file->isOpen()) {
file->open(QIODevice::WriteOnly);
}
m_d->file.reset(file.data());
Q_EMIT fileChanged();
}
QString KazvIODownloadJob::fileName() {
return m_d->file->fileName();
}
void KazvIODownloadJob::connectJob()
{
KazvIOBaseJob::connectJob();
connect(this->job(), &KIO::TransferJob::data, this, [this](KJob * /* job */, const QByteArray &data) {
m_d->file->write(data);
});
connect(this->job(), &KJob::result, this, [this](KJob *job) {
if (job->error()) {
m_d->file->cancelWriting();
}
m_d->file->commit();
});
}
struct KazvIOUploadJobPrivate
{
QSharedPointer<QFile> file;
QString response;
QPointer<MatrixRoom> room;
QUrl localFileUrl; // For send media file message
};
KazvIOUploadJob::KazvIOUploadJob(QObject *parent)
: KazvIOBaseJob(parent)
, m_d(new KazvIOUploadJobPrivate)
{
}
KazvIOUploadJob::~KazvIOUploadJob() = default;
QPointer<QFile> KazvIOUploadJob::file()
{
return m_d->file.data();
}
void KazvIOUploadJob::setFile(QPointer<QFile> file)
{
if (!file->isOpen()) {
file->open(QIODevice::ReadOnly);
}
m_d->file.reset(file.data());
Q_EMIT fileChanged();
}
QString KazvIOUploadJob::response()
{
return m_d->response;
}
QPointer<MatrixRoom> KazvIOUploadJob::room()
{
return m_d->room;
}
void KazvIOUploadJob::setRoom(QPointer<MatrixRoom> room)
{
m_d->room = room;
Q_EMIT roomChanged();
}
QUrl KazvIOUploadJob::localFileUrl()
{
return m_d->localFileUrl;
}
void KazvIOUploadJob::setLocalFileUrl(QUrl localFileUrl)
{
m_d->localFileUrl = localFileUrl;
Q_EMIT localFileUrlChanged();
}
QString KazvIOUploadJob::fileName()
{
return m_d->file->fileName();
}
void KazvIOUploadJob::connectJob()
{
KazvIOBaseJob::connectJob();
connect(this->job(), &KIO::TransferJob::data, this, [this](KJob * /* job */, const QByteArray &data) {
m_d->response.append(data);
Q_EMIT responseChanged();
});
connect(this->job(), &KJob::result, this, [this](KJob *job) {
m_d->file->close();
if (job->error()) {
m_d->response.clear();
return;
}
json j = json::parse(m_d->response.toStdString());
auto mxcUri = j["content_uri"].get<std::string>();
m_d->room->sendMediaFileMessage(m_d->localFileUrl, QString(mxcUri.data()));
});
}
diff --git a/src/kazv-io-job.hpp b/src/kazv-io-job.hpp
index b884b46..0296ec1 100644
--- a/src/kazv-io-job.hpp
+++ b/src/kazv-io-job.hpp
@@ -1,120 +1,121 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include "matrix-room.hpp"
#include <QObject>
#include <QPointer>
#include <QSaveFile>
#include <QFile>
#include <QString>
#include <QByteArray>
#include <QUrl>
#include <KIO/TransferJob>
#include <memory>
#include <optional>
struct KazvIOBaseJobPrivate;
class KazvIOBaseJob : public QObject
{
Q_OBJECT
Q_PROPERTY(QPointer<KIO::TransferJob> job READ job WRITE setJob NOTIFY jobChanged)
Q_PROPERTY(float progress READ progress NOTIFY progressChanged)
std::unique_ptr<KazvIOBaseJobPrivate> m_d;
public:
KazvIOBaseJob(QObject *parent = 0);
~KazvIOBaseJob();
QPointer<KIO::TransferJob> job();
void setJob(QPointer<KIO::TransferJob> job);
float progress();
/**
* Only use it after emitted the result signal
*/
Q_INVOKABLE void suspend();
Q_INVOKABLE void resume();
Q_INVOKABLE void cancel();
Q_INVOKABLE bool isSuspended();
Q_INVOKABLE bool isResulted();
+ Q_INVOKABLE bool error();
Q_SIGNALS:
void jobChanged();
void progressChanged();
void result();
void success();
void failure();
protected Q_SLOTS:
virtual void connectJob();
void emitProgressChanged(KJob * job, unsigned long percent);
};
struct KazvIODownloadJobPrivate;
class KazvIODownloadJob : public KazvIOBaseJob
{
Q_OBJECT
Q_PROPERTY(QPointer<QSaveFile> file READ file WRITE setFile NOTIFY fileChanged)
std::unique_ptr<KazvIODownloadJobPrivate> m_d;
public:
KazvIODownloadJob(QObject *parent = 0);
~KazvIODownloadJob();
QPointer<QSaveFile> file();
void setFile(QPointer<QSaveFile> file);
Q_INVOKABLE QString fileName();
Q_SIGNALS:
void fileChanged();
protected Q_SLOTS:
void connectJob() override;
};
struct KazvIOUploadJobPrivate;
class KazvIOUploadJob : public KazvIOBaseJob
{
Q_OBJECT
Q_PROPERTY(QPointer<QFile> file READ file WRITE setFile NOTIFY fileChanged)
Q_PROPERTY(QString response READ response NOTIFY responseChanged)
Q_PROPERTY(QPointer<MatrixRoom> room READ room WRITE setRoom NOTIFY roomChanged)
Q_PROPERTY(QUrl localFileUrl READ localFileUrl WRITE setLocalFileUrl NOTIFY localFileUrlChanged)
std::unique_ptr<KazvIOUploadJobPrivate> m_d;
public:
KazvIOUploadJob(QObject *parent = 0);
~KazvIOUploadJob();
QPointer<QFile> file();
void setFile(QPointer<QFile> file);
QString response();
QPointer<MatrixRoom> room();
void setRoom(QPointer<MatrixRoom> room);
QUrl localFileUrl();
void setLocalFileUrl(QUrl localFileUrl);
Q_INVOKABLE QString fileName();
Q_SIGNALS:
void fileChanged();
void responseChanged();
void roomChanged();
void localFileUrlChanged();
void result();
protected Q_SLOTS:
void connectJob() override;
};
diff --git a/src/kazv-io-manager.cpp b/src/kazv-io-manager.cpp
index 5a9b959..f7e8966 100644
--- a/src/kazv-io-manager.cpp
+++ b/src/kazv-io-manager.cpp
@@ -1,108 +1,109 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2022 nannanko <nannanko@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "kazv-io-manager.hpp"
#include "kazv-io-job.hpp"
#include "matrix-room.hpp"
#include "upload-job-model.hpp"
#include <api/csapi/content-repo.hpp>
#include <file-desc.hpp>
#include <QObject>
#include <QIODevice>
#include <QFile>
#include <QSaveFile>
#include <QPointer>
#include <QSharedPointer>
#include <QUrl>
#include <QMap>
#include <QMultiMap>
#include <string>
struct KazvIOManagerPrivate
{
QMap<QString, QPointer<KazvIODownloadJob>> downloadJobs;
QMap<QString, QPointer<UploadJobModel>> uploadJobs;
};
KazvIOManager::KazvIOManager(QObject *parent)
: QObject(parent)
, m_d(new KazvIOManagerPrivate)
{
}
KazvIOManager::~KazvIOManager() = default;
KazvIOBaseJob *KazvIOManager::startNewDownloadJob(const QUrl &serverUrl, const QUrl &localFileUrl, const QString &jobId)
{
auto downloadJob = QPointer<KazvIODownloadJob>(new KazvIODownloadJob());
downloadJob->setJob(KIO::get(serverUrl));
downloadJob->setFile(new QSaveFile(localFileUrl.path(), downloadJob.data()));
m_d->downloadJobs[jobId] = downloadJob;
return downloadJob.data();
}
KazvIOBaseJob *KazvIOManager::startNewUploadJob(const QUrl &serverUrl, const QUrl &localFileUrl, const QString &token, MatrixRoom *room)
{
auto uploadJob = QPointer<KazvIOUploadJob>(new KazvIOUploadJob());
uploadJob->setFile(new QFile(localFileUrl.path(), uploadJob.data()));
auto kazvUploadJob = Kazv::Api::UploadContentJob(serverUrl.toString().toStdString(), token.toStdString(), Kazv::FileDesc(std::string()));
uploadJob->setJob(KIO::http_post(QString(kazvUploadJob.url().data()), uploadJob->file().data()));
uploadJob->job()->addMetaData(QString("content-type") , QMimeDatabase().mimeTypeForFile(localFileUrl.path()).name());
uploadJob->job()->addMetaData("customHTTPHeader", QStringLiteral("Authorization: ").append(kazvUploadJob.requestHeader()->at("Authorization").data()));
uploadJob->job()->addMetaData("PropagateHttpHeader", "true");
uploadJob->setRoom(room);
uploadJob->setLocalFileUrl(localFileUrl);
auto roomId = room->roomId();
connect(uploadJob.data(), &KazvIOBaseJob::success, this, [this, roomId, uploadJob]() {
m_d->uploadJobs[roomId]->removeJob(uploadJob);
});
if (!m_d->uploadJobs.contains(roomId) || m_d->uploadJobs[roomId].isNull()) {
m_d->uploadJobs[roomId] = new UploadJobModel(this);
}
m_d->uploadJobs[roomId]->addJob(uploadJob);
return uploadJob.data();
}
KazvIOBaseJob *KazvIOManager::getDownloadJob(const QString &jobId)
{
auto targetJob = m_d->downloadJobs.find(jobId);
if (targetJob == m_d->downloadJobs.end()) {
return nullptr;
}
return targetJob.value().data();
}
void KazvIOManager::deleteDownloadJob(const QString &jobId)
{
m_d->downloadJobs[jobId]->deleteLater();
m_d->downloadJobs.remove(jobId);
}
UploadJobModel *KazvIOManager::getUploadJobs(const QString &roomId)
{
if (!m_d->uploadJobs.contains(roomId) || m_d->uploadJobs[roomId].isNull()) {
m_d->uploadJobs[roomId] = new UploadJobModel(this);
}
return m_d->uploadJobs[roomId].data();
}
void KazvIOManager::deleteUploadJob(const QString &roomId, KazvIOBaseJob *job)
{
m_d->uploadJobs[roomId]->removeJob(QPointer<KazvIOUploadJob>(qobject_cast<KazvIOUploadJob*>(job)));
+ qDebug() << m_d->uploadJobs[roomId]->rowCount();
}
void KazvIOManager::deleteModelIfEmpty(const QString &roomId)
{
if (!m_d->uploadJobs.contains(roomId)) {
return;
} else if (m_d->uploadJobs[roomId]->rowCount() == 0) {
m_d->uploadJobs[roomId]->deleteLater();
m_d->uploadJobs.remove(roomId);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 9:04 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55448
Default Alt Text
(15 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment