Commit ebcccec2 authored by Linus Jahn's avatar Linus Jahn 🍙 Committed by Jonah Brüchert

media-sharing: Display progress bar when uploading

parent 31e2f549
Pipeline #340 passed with stages
in 5 minutes and 29 seconds
......@@ -19,6 +19,7 @@ set(KAIDAN_SOURCES
${CURDIR}/StatusBar.cpp
${CURDIR}/UploadManager.cpp
${CURDIR}/EmojiModel.cpp
${CURDIR}/TransferCache.cpp
# needed to trigger moc generation
${CURDIR}/Enums.h
......
......@@ -60,7 +60,8 @@ ClientWorker::ClientWorker(Caches *caches, Kaidan *kaidan, bool enableLogging, Q
caches->avatarStorage, vCardManager, this);
msgHandler = new MessageHandler(kaidan, client, caches->msgModel, this);
discoManager = new DiscoveryManager(client, this);
uploadManager = new UploadManager(kaidan, client, caches->msgModel, rosterManager, this);
uploadManager = new UploadManager(kaidan, client, caches->msgModel, rosterManager,
caches->transferCache, this);
connect(client, &QXmppClient::presenceReceived,
caches->presCache, &PresenceCache::updatePresenceRequested);
......
......@@ -47,6 +47,7 @@ class QGuiApplication;
#include "RosterModel.h"
#include "AvatarFileStorage.h"
#include "PresenceCache.h"
#include "TransferCache.h"
class LogHandler;
class Kaidan;
class ClientWorker;
......@@ -91,6 +92,7 @@ public:
rosterModel(new RosterModel(database->getDatabase(), parent)),
avatarStorage(new AvatarFileStorage(parent)),
presCache(new PresenceCache(parent)),
transferCache(new TransferCache(parent)),
settings(new QSettings(APPLICATION_NAME, APPLICATION_NAME))
{
}
......@@ -101,6 +103,7 @@ public:
delete rosterModel;
delete avatarStorage;
delete presCache;
delete transferCache;
delete settings;
}
......@@ -108,6 +111,7 @@ public:
RosterModel *rosterModel;
AvatarFileStorage *avatarStorage;
PresenceCache *presCache;
TransferCache* transferCache;
QSettings *settings;
};
......
......@@ -58,10 +58,11 @@ class Kaidan : public QObject
{
Q_OBJECT
Q_PROPERTY(RosterModel* rosterModel READ getRosterModel NOTIFY rosterModelChanged)
Q_PROPERTY(MessageModel* messageModel READ getMessageModel NOTIFY messageModelChanged)
Q_PROPERTY(RosterModel* rosterModel READ getRosterModel CONSTANT)
Q_PROPERTY(MessageModel* messageModel READ getMessageModel CONSTANT)
Q_PROPERTY(AvatarFileStorage* avatarStorage READ getAvatarStorage NOTIFY avatarStorageChanged)
Q_PROPERTY(PresenceCache* presenceCache READ getPresenceCache NOTIFY presenceCacheChanged)
Q_PROPERTY(PresenceCache* presenceCache READ getPresenceCache CONSTANT)
Q_PROPERTY(TransferCache* transferCache READ getTransferCache CONSTANT)
Q_PROPERTY(quint8 connectionState READ getConnectionState NOTIFY connectionStateChanged)
Q_PROPERTY(quint8 disconnReason READ getDisconnReason NOTIFY disconnReasonChanged)
Q_PROPERTY(QString jid READ getJid WRITE setJid NOTIFY jidChanged)
......@@ -222,6 +223,11 @@ public:
return caches->presCache;
}
TransferCache* getTransferCache() const
{
return caches->transferCache;
}
/**
* Adds XMPP URI to open as soon as possible
*/
......@@ -258,10 +264,7 @@ public:
Q_INVOKABLE QString formatMessage(QString message);
signals:
void rosterModelChanged();
void messageModelChanged();
void avatarStorageChanged();
void presenceCacheChanged();
/**
* Emitted, when the client's connection state has changed (e.g. when
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2018 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TransferCache.h"
#include "qxmpp-exts/QXmppUploadManager.h"
#include <QMutexLocker>
TransferJob::TransferJob(qint64 bytesTotal)
: QObject(), progress(0.0), bytesSent(0), bytesTotal(bytesTotal)
{
}
void TransferJob::setProgress(qreal progress)
{
if (this->progress == progress)
return;
this->progress = progress;
emit progressChanged();
}
void TransferJob::setBytesSent(qint64 bytesSent)
{
if (this->bytesSent == bytesSent)
return;
this->bytesSent = bytesSent;
emit bytesSentChanged();
setProgress((qreal) bytesSent / (qreal) bytesTotal);
}
void TransferJob::setBytesTotal(qint64 bytesTotal)
{
if (this->bytesTotal == bytesTotal)
return;
this->bytesTotal = bytesTotal;
emit bytesTotalChanged();
setProgress((qreal) bytesSent / (qreal) bytesTotal);
}
TransferCache::TransferCache(QObject *parent)
: QObject(parent)
{
connect(this, &TransferCache::addUploadRequested, this, &TransferCache::addUpload);
connect(this, &TransferCache::removeUploadRequested,
this, &TransferCache::removeUpload);
connect(this, &TransferCache::setUploadBytesSentRequested,
this, &TransferCache::setUploadBytesSent);
}
TransferCache::~TransferCache()
{
// wait for other threads to finish
QMutexLocker locker(&mutex);
}
void TransferCache::addUpload(const QString& msgId, qint64 bytesTotal)
{
QMutexLocker locker(&mutex);
uploads.insert(msgId, new TransferJob(bytesTotal));
locker.unlock();
emit jobsChanged();
}
void TransferCache::removeUpload(const QString& msgId)
{
QMutexLocker locker(&mutex);
delete uploads[msgId];
uploads.remove(msgId);
locker.unlock();
emit jobsChanged();
}
bool TransferCache::hasUpload(QString msgId) const
{
QMutexLocker locker(&mutex);
return uploads.contains(msgId);
}
TransferJob* TransferCache::uploadByMessageId(QString msgId) const
{
QMutexLocker locker(&mutex);
TransferJob* job = uploads.value(msgId);
if (job == nullptr)
return emptyJob;
return job;
}
void TransferCache::setUploadBytesSent(const QString& msgId, qint64 bytesSent)
{
uploadByMessageId(msgId)->setBytesSent(bytesSent);
}
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2018 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRANSFERCACHE_H
#define TRANSFERCACHE_H
#include <QObject>
#include <QMap>
#include <QMutex>
/**
* @class TransferJob Upload/download progress information
*/
class TransferJob : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal progress MEMBER progress NOTIFY progressChanged)
Q_PROPERTY(qint64 bytesSent MEMBER bytesSent NOTIFY bytesSentChanged)
Q_PROPERTY(qint64 bytesTotal MEMBER bytesTotal NOTIFY bytesTotalChanged)
public:
TransferJob(qint64 bytesTotal);
Q_INVOKABLE void setProgress(qreal progress);
Q_INVOKABLE void setBytesSent(qint64 bytesSent);
Q_INVOKABLE void setBytesTotal(qint64 bytesTotal);
signals:
void progressChanged();
void bytesSentChanged();
void bytesTotalChanged();
private:
qreal progress;
qint64 bytesSent;
qint64 bytesTotal;
};
/**
* @class TransferCache Caching upload and download meta.
*
* This class is thread-safe.
*/
class TransferCache : public QObject
{
Q_OBJECT
public:
TransferCache(QObject *parent = nullptr);
~TransferCache();
/**
* Returns true if the cache contains an upload for the specified message id.
*/
Q_INVOKABLE bool hasUpload(QString msgId) const;
/**
* Returns the upload associated with the message id (used for progress)
*/
Q_INVOKABLE TransferJob* uploadByMessageId(QString msgId) const;
public slots:
Q_INVOKABLE void addUpload(const QString &msgId, qint64 bytesTotal);
Q_INVOKABLE void removeUpload(const QString& msgId);
Q_INVOKABLE void setUploadBytesSent(const QString& msgId, qint64 bytesSent);
signals:
/**
* @brief Emitted when a job was added or removed; useful for getting notified
* about changes of hasUpload().
*/
void jobsChanged();
void addUploadRequested(const QString& msgId, qint64 bytesTotal);
void removeUploadRequested(const QString& msgId);
void setUploadBytesSentRequested(const QString& msgId, qint64 bytesSent);
private:
QMap<QString, TransferJob*> uploads;
TransferJob* emptyJob;
mutable QMutex mutex;
};
#endif // TRANSFERCACHE_H
......@@ -32,11 +32,13 @@
#include "Kaidan.h"
#include "MessageHandler.h"
#include "RosterManager.h"
#include "TransferCache.h"
// QXmpp
#include <QXmppUtils.h>
// Qt
#include <QMimeDatabase>
#include <QMimeType>
#include <QMutexLocker>
#include <QDateTime>
#include <QBuffer>
#include <QImage>
......@@ -44,9 +46,10 @@
#include <QFileInfo>
UploadManager::UploadManager(Kaidan *kaidan, QXmppClient *client, MessageModel *msgModel,
RosterManager *rosterManager, QObject *parent)
RosterManager* rosterManager, TransferCache* transfers,
QObject* parent)
: QObject(parent), kaidan(kaidan), client(client), msgModel(msgModel),
rosterManager(rosterManager)
rosterManager(rosterManager), transfers(transfers)
{
client->addExtension(&manager);
......@@ -78,14 +81,15 @@ void UploadManager::sendFile(QString jid, QString fileUrl, QString body)
qDebug() << "[client] [UploadManager] Adding upload for file:" << fileUrl;
QFileInfo file(QUrl(fileUrl).toLocalFile());
int id = manager.uploadFile(file);
const QXmppHttpUpload* upload = manager.uploadFile(file);
QMimeType mimeType = QMimeDatabase().mimeTypeForFile(file);
const QString msgId = QXmppUtils::generateStanzaHash(48);
auto *msg = new MessageModel::Message();
msg->author = client->configuration().jidBare();
msg->recipient = jid;
msg->id = QXmppUtils::generateStanzaHash(48);
msg->id = msgId;
msg->sentByMe = true;
msg->message = body;
msg->type = MessageModel::messageTypeFromMimeType(mimeType);
......@@ -95,9 +99,11 @@ void UploadManager::sendFile(QString jid, QString fileUrl, QString body)
msg->mediaLastModified = file.lastModified().currentMSecsSinceEpoch();
msg->mediaLocation = file.filePath();
// cache message and upload
emit transfers->addUploadRequested(msgId, upload->bytesTotal());
messages.insert(upload->id(), msg);
emit msgModel->addMessageRequested(*msg);
// message cache to edit on success/failure
messages.insert(id, msg);
// update last message
QString lastMessage = tr("File");
......@@ -105,6 +111,10 @@ void UploadManager::sendFile(QString jid, QString fileUrl, QString body)
lastMessage = lastMessage.append(": ").append(body);
rosterManager->handleSendMessage(jid, lastMessage);
connect(upload, &QXmppHttpUpload::bytesSentChanged, this, [upload, this, msgId] () {
emit transfers->setUploadBytesSentRequested(msgId, upload->bytesSent());
});
}
void UploadManager::handleUploadSucceeded(const QXmppHttpUpload *upload)
......@@ -135,14 +145,13 @@ void UploadManager::handleUploadSucceeded(const QXmppHttpUpload *upload)
// TODO: handle error
messages.remove(upload->id());
}
void UploadManager::handleUploadProgressed(const QXmppHttpUpload*)
{
emit transfers->removeUploadRequested(originalMsg->id);
}
void UploadManager::handleUploadFailed(const QXmppHttpUpload *upload)
{
qDebug() << "[client] [UploadManager] A file upload has failed.";
const QString &msgId = messages.value(upload->id())->id;
messages.remove(upload->id());
emit transfers->removeUploadRequested(msgId);
}
......@@ -45,6 +45,7 @@ using namespace Enums;
class Kaidan;
class RosterManager;
class TransferCache;
/**
* @class UploadManager Class for handling and starting HTTP File Uploads
......@@ -57,8 +58,9 @@ public:
/**
* Default constructor
*/
UploadManager(Kaidan *kaidan, QXmppClient *client, MessageModel *msgModel,
RosterManager *rosterManager, QObject *parent = nullptr);
UploadManager(Kaidan* kaidan, QXmppClient* client, MessageModel* msgModel,
RosterManager* rosterManager, TransferCache* transfers,
QObject* parent = nullptr);
signals:
/**
......@@ -73,7 +75,6 @@ public slots:
void sendFile(QString jid, QString filePath, QString message);
void handleUploadFailed(const QXmppHttpUpload *upload);
void handleUploadProgressed(const QXmppHttpUpload *upload);
void handleUploadSucceeded(const QXmppHttpUpload *upload);
private:
......@@ -82,6 +83,7 @@ private:
QXmppUploadManager manager;
MessageModel *msgModel;
RosterManager *rosterManager;
TransferCache* transfers;
QMap<int, MessageModel::Message*> messages;
};
......
......@@ -42,6 +42,7 @@
// QXmpp
#include <QXmppClient.h>
#include "qxmpp-exts/QXmppUploadManager.h"
// Kaidan
#include "Kaidan.h"
......@@ -49,6 +50,7 @@
#include "MessageModel.h"
#include "AvatarFileStorage.h"
#include "PresenceCache.h"
#include "UploadManager.h"
#include "Globals.h"
#include "Enums.h"
#include "StatusBar.h"
......@@ -166,6 +168,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
qRegisterMetaType<MessageType>("MessageType");
qRegisterMetaType<DisconnectionReason>("DisconnectionReason");
qRegisterMetaType<EmojiModel*>("EmojiModel");
qRegisterMetaType<TransferJob*>("TransferJob*");
// Qt-Translator
QTranslator qtTranslator;
......
......@@ -126,6 +126,7 @@ Kirigami.ScrollablePage {
model: kaidan.messageModel
delegate: ChatMessage {
msgId: model.id
sentByMe: model.recipient !== kaidan.jid
messageBody: model.message
dateTime: new Date(model.timestamp)
......
......@@ -38,6 +38,7 @@ import im.kaidan.kaidan 1.0
RowLayout {
id: root
property string msgId
property bool sentByMe: true
property string messageBody
property date dateTime
......@@ -49,6 +50,12 @@ RowLayout {
property var textEdit
property bool isLastMessage
property bool edited
property var upload: {
if (mediaType != Enums.MessageText && mediaGetUrl == ""
&& kaidan.transferCache.hasUpload(msgId)) {
kaidan.transferCache.uploadByMessageId(model.id)
}
}
// own messages are on the right, others on the left
layoutDirection: sentByMe ? Qt.RightToLeft : Qt.LeftToRight
......@@ -164,6 +171,23 @@ RowLayout {
// message meta: date, isRead
RowLayout {
Controls.ProgressBar {
id: progressBar
value: upload.progress
visible: kaidan.transferCache.hasUpload(msgId)
function updateVisibility() {
progressBar.visible = kaidan.transferCache.hasUpload(msgId)
}
Component.onCompleted: {
kaidan.transferCache.jobsChanged.connect(updateVisibility)
}
Component.onDestruction: {
kaidan.transferCache.jobsChanged.disconnect(updateVisibility)
}
}
Controls.Label {
id: dateLabel
text: Qt.formatDateTime(dateTime, "dd. MMM yyyy, hh:mm")
......
......@@ -30,6 +30,7 @@
#include <QMimeDatabase>
#include <QMimeType>
#include <QMutexLocker>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
......@@ -38,13 +39,13 @@
QXmppHttpUpload::QXmppHttpUpload(QXmppUploadManager *manager)
: QXmppLoggable(), m_manager(manager), m_netManager(new QNetworkAccessManager())
{
connect(this, &QXmppHttpUpload::uploadProgressed, this, &QXmppHttpUpload::handleProgressed);
}
QXmppHttpUpload::QXmppHttpUpload(const QXmppHttpUpload &upload)
: QXmppLoggable(), m_manager(upload.m_manager), m_customFileName(upload.m_customFileName),
: QXmppLoggable(), m_manager(upload.m_manager), m_customFileName(upload.m_customFileName),
m_fileInfo(upload.m_fileInfo), m_requestId(upload.m_requestId),
m_requestError(upload.m_requestError), m_slot(upload.m_slot), m_bytesSent(upload.m_bytesSent),
m_requestError(upload.m_requestError), m_slot(upload.m_slot),
m_bytesSent(upload.m_bytesSent), m_bytesTotal(upload.m_bytesTotal),
m_uploadError(upload.m_uploadError), m_netManager(new QNetworkAccessManager())
{
}
......@@ -52,8 +53,6 @@ QXmppHttpUpload::QXmppHttpUpload(const QXmppHttpUpload &upload)
QXmppHttpUpload::~QXmppHttpUpload()
{
delete m_netManager;
// if (m_putReply)
// delete m_putReply;
}
QXmppHttpUpload& QXmppHttpUpload::operator=(const QXmppHttpUpload &other)
......@@ -66,6 +65,7 @@ QXmppHttpUpload& QXmppHttpUpload::operator=(const QXmppHttpUpload &other)
m_requestError = other.m_requestError;
m_slot = other.m_slot;
m_bytesSent = other.m_bytesSent;
m_bytesTotal = other.m_bytesTotal;
m_uploadError = other.m_uploadError;
}
return *this;
......@@ -119,6 +119,7 @@ QFileInfo QXmppHttpUpload::fileInfo() const
void QXmppHttpUpload::setFileInfo(const QFileInfo &fileInfo)
{
m_fileInfo = fileInfo;
m_bytesTotal = m_fileInfo.size();
}
QXmppHttpUploadSlotIq QXmppHttpUpload::slot() const
......@@ -141,22 +142,40 @@ void QXmppHttpUpload::setRequestError(const QXmppHttpUploadRequestIq &requestErr
m_requestError = requestError;
}
bool QXmppHttpUpload::started() const
{
return m_started;
}
/// Returns the number of bytes sent to the server.
qint64 QXmppHttpUpload::progress() const
qint64 QXmppHttpUpload::bytesSent() const
{
return m_bytesSent;
}
void QXmppHttpUpload::handleProgressed(qint64 sent, qint64)
qint64 QXmppHttpUpload::bytesTotal() const
{
m_bytesSent = sent;
return m_bytesTotal;
}
void QXmppHttpUpload::handleProgressed(qint64 sent, qint64 total)
{
if (m_bytesSent != sent) {
m_bytesSent = sent;
emit bytesSentChanged();
}
if (m_bytesTotal != total) {
m_bytesTotal = total;
emit bytesTotalChanged();
}
}
/// Starts uploading the file. It assumes that a valid slot and fileInfo are set.
void QXmppHttpUpload::startUpload()
{
m_started = true;
QNetworkRequest request(m_slot.putUrl());
// include the file's content-type
......@@ -180,21 +199,28 @@ void QXmppHttpUpload::startUpload()
m_putReply = m_netManager->put(request, file);
connect(m_putReply, &QNetworkReply::finished, this, &QXmppHttpUpload::uploadFinished);
connect(m_putReply, &QNetworkReply::uploadProgress, this, &QXmppHttpUpload::uploadProgressed);
connect(m_putReply, &QNetworkReply::uploadProgress, this, &QXmppHttpUpload::handleProgressed);
connect(m_putReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
this, &QXmppHttpUpload::uploadFailed);
// delete file object after upload
connect(m_putReply, &QNetworkReply::finished, file, &QFile::deleteLater);
connect(m_putReply, &QNetworkReply::finished, [this, file] () {
file->deleteLater();
m_started = false;
});
connect(m_putReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
file, &QFile::deleteLater);
[this, file] () {
file->deleteLater();
m_started = false;
});
}
void QXmppHttpUpload::abortUpload()
void QXmppHttpUpload::abort()
{
if (m_putReply) {
if (m_started) {
m_putReply->abort();
emit uploadFailed(QNetworkReply::NoError);
m_started = false;
}
}
......@@ -207,6 +233,13 @@ QXmppUploadManager::QXmppUploadManager()
this, &QXmppUploadManager::handleRequestError);
}
QXmppUploadManager::~QXmppUploadManager()
{
for (QXmppHttpUpload *upload : m_uploads) {
upload->abort();
}
}
/// Requests an upload slot and starts uploading the file
///
/// \param file The file to be uploaded.
......@@ -215,7 +248,7 @@ QXmppUploadManager::QXmppUploadManager()
/// \return Returns the upload's id. The id is unique per session (as long as the UploadManager
/// exists).
int QXmppUploadManager::uploadFile(const QFileInfo &file, bool allowParallel, QString customFileName)
const QXmppHttpUpload* QXmppUploadManager::uploadFile(const QFileInfo &file, bool allowParallel, QString customFileName)
{
auto *upload = new QXmppHttpUpload(this);
upload->setFileInfo(file);
......@@ -225,8 +258,6 @@ int QXmppUploadManager::uploadFile(const QFileInfo &file, bool allowParallel, QS
// connect signals
connect(upload, &QXmppHttpUpload::uploadFinished,
this, &QXmppUploadManager::handleUploadFinished);
connect(upload, &QXmppHttpUpload::uploadProgressed,
this, &QXmppUploadManager::handleUploadProgressed);
connect(upload, &QXmppHttpUpload::uploadFailed,
this, &QXmppUploadManager::handleUploadFailed);
......@@ -235,7 +266,7 @@ int QXmppUploadManager::uploadFile(const QFileInfo &file, bool allowParallel, QS
if (m_runningJobs == 0 || allowParallel)
startNextUpload();
return upload->id();
return upload;
}
void QXmppUploadManager::startNextUpload()
......@@ -262,8 +293,6 @@ void QXmppUploadManager::startNextUpload()
startNextUpload();
return;
}
emit uploadStarted(upload);
}
/// Handles requested upload slots
......@@ -305,13 +334,6 @@ void QXmppUploadManager::handleRequestError(const QXmppHttpUploadRequestIq &requ
}
}
/// Handles upload progress
void QXmppUploadManager::handleUploadProgressed(qint64 sent, qint64 total)
{
qDebug() << "progress" << sent << total;
}
/// Handles finished uploads
void QXmppUploadManager::handleUploadFinished()
......
......@@ -34,6 +34,7 @@
#include <QFile>
#include <QFileInfo>
#include <QNetworkReply>
#include <QMutex>
#include "QXmppUploadRequestManager.h"
class QNetworkAccessManager;
......@@ -45,6 +46,8 @@ class QXmppUploadManager; // needed for QXmppHttpUpload
class QXMPP_EXPORT QXmppHttpUpload : public QXmppLoggable
{
Q_OBJECT
Q_PROPERTY(qint64 bytesSent READ bytesSent NOTIFY bytesSentChanged)
Q_PROPERTY(qint64 bytesTotal READ bytesTotal NOTIFY bytesTotalChanged)
public:
QXmppHttpUpload(QXmppUploadManager *manager);
......@@ -71,16 +74,20 @@ public:
QXmppHttpUploadSlotIq slot() const;
void setSlot(const QXmppHttpUploadSlotIq &slot);
qint64 progress() const;
qint64 bytesSent() const;
qint64 bytesTotal() const;
bool started() const;
public slots:
void startUpload();
void abortUpload();
void abort();
signals:
void uploadFinished();
void uploadProgressed(qint64 sent, qint64 total);
void uploadFailed(QNetworkReply::NetworkError code);
void bytesSentChanged();