diff options
-rw-r--r-- | avatar.cpp | 84 | ||||
-rw-r--r-- | avatar.h | 22 | ||||
-rw-r--r-- | room.cpp | 8 | ||||
-rw-r--r-- | user.cpp | 40 | ||||
-rw-r--r-- | user.h | 3 |
5 files changed, 105 insertions, 52 deletions
@@ -30,10 +30,13 @@ using namespace QMatrixClient; class Avatar::Private { public: - Private(Connection* c, QIcon di) : _connection(c), _defaultIcon(di) { } - QImage get(QSize size, Avatar::notifier_t notifier) const; + explicit Private(QIcon di, QUrl url = {}) + : _defaultIcon(di), _url(url) + { } + QImage get(Connection* connection, QSize size, + get_callback_t callback) const; + bool upload(UploadContentJob* job, upload_callback_t callback); - Connection* _connection; const QIcon _defaultIcon; QUrl _url; @@ -42,24 +45,52 @@ class Avatar::Private mutable std::vector<QPair<QSize, QImage>> _scaledImages; mutable QSize _requestedSize; mutable bool _valid = false; - mutable QPointer<MediaThumbnailJob> _ongoingRequest = nullptr; - mutable std::vector<notifier_t> notifiers; + mutable QPointer<MediaThumbnailJob> _thumbnailRequest = nullptr; + mutable QPointer<BaseJob> _uploadRequest = nullptr; + mutable std::vector<get_callback_t> callbacks; + mutable get_callback_t uploadCallback; }; -Avatar::Avatar(Connection* connection, QIcon defaultIcon) - : d(new Private { connection, std::move(defaultIcon) }) +Avatar::Avatar(QIcon defaultIcon) + : d(std::make_unique<Private>(std::move(defaultIcon))) { } +Avatar::Avatar(QUrl url, QIcon defaultIcon) + : d(std::make_unique<Private>(std::move(defaultIcon), std::move(url))) +{ } + +Avatar::Avatar(Avatar&&) = default; + Avatar::~Avatar() = default; -QImage Avatar::get(int dimension, notifier_t notifier) const +Avatar& Avatar::operator=(Avatar&&) = default; + +QImage Avatar::get(Connection* connection, int dimension, + get_callback_t callback) const { - return d->get({dimension, dimension}, notifier); + return d->get(connection, {dimension, dimension}, callback); } -QImage Avatar::get(int width, int height, notifier_t notifier) const +QImage Avatar::get(Connection* connection, int width, int height, + get_callback_t callback) const { - return d->get({width, height}, notifier); + return d->get(connection, {width, height}, callback); +} + +bool Avatar::upload(Connection* connection, const QString& fileName, + upload_callback_t callback) const +{ + if (isJobRunning(d->_uploadRequest)) + return false; + return d->upload(connection->uploadFile(fileName), callback); +} + +bool Avatar::upload(Connection* connection, QIODevice* source, + upload_callback_t callback) const +{ + if (isJobRunning(d->_uploadRequest) || !source->isReadable()) + return false; + return d->upload(connection->uploadContent(source), callback); } QString Avatar::mediaId() const @@ -67,28 +98,29 @@ QString Avatar::mediaId() const return d->_url.authority() + d->_url.path(); } -QImage Avatar::Private::get(QSize size, Avatar::notifier_t notifier) const +QImage Avatar::Private::get(Connection* connection, QSize size, + get_callback_t callback) const { // FIXME: Alternating between longer-width and longer-height requests // is a sure way to trick the below code into constantly getting another // image from the server because the existing one is alleged unsatisfactory. // This is plain abuse by the client, though; so not critical for now. - if( ( !(_valid || _ongoingRequest) + if( ( !(_valid || _thumbnailRequest) || size.width() > _requestedSize.width() || size.height() > _requestedSize.height() ) && _url.isValid() ) { qCDebug(MAIN) << "Getting avatar from" << _url.toString(); _requestedSize = size; - if (isJobRunning(_ongoingRequest)) - _ongoingRequest->abandon(); - notifiers.emplace_back(std::move(notifier)); - _ongoingRequest = _connection->getThumbnail(_url, size); - QObject::connect( _ongoingRequest, &MediaThumbnailJob::success, [this] + if (isJobRunning(_thumbnailRequest)) + _thumbnailRequest->abandon(); + callbacks.emplace_back(std::move(callback)); + _thumbnailRequest = connection->getThumbnail(_url, size); + QObject::connect( _thumbnailRequest, &MediaThumbnailJob::success, [this] { _valid = true; - _originalImage = _ongoingRequest->scaledThumbnail(_requestedSize); + _originalImage = _thumbnailRequest->scaledThumbnail(_requestedSize); _scaledImages.clear(); - for (auto n: notifiers) + for (auto n: callbacks) n(); }); } @@ -111,6 +143,16 @@ QImage Avatar::Private::get(QSize size, Avatar::notifier_t notifier) const return result; } +bool Avatar::Private::upload(UploadContentJob* job, upload_callback_t callback) +{ + _uploadRequest = job; + if (!isJobRunning(_uploadRequest)) + return false; + _uploadRequest->connect(_uploadRequest, &BaseJob::success, + [job,callback] { callback(job->contentUri()); }); + return true; +} + QUrl Avatar::url() const { return d->_url; } bool Avatar::updateUrl(const QUrl& newUrl) @@ -127,6 +169,8 @@ bool Avatar::updateUrl(const QUrl& newUrl) } d->_url = newUrl; d->_valid = false; + if (isJobRunning(d->_thumbnailRequest)) + d->_thumbnailRequest->abandon(); return true; } @@ -22,6 +22,7 @@ #include <QtCore/QUrl> #include <functional> +#include <memory> namespace QMatrixClient { @@ -30,13 +31,24 @@ namespace QMatrixClient class Avatar { public: - explicit Avatar(Connection* connection, QIcon defaultIcon = {}); + explicit Avatar(QIcon defaultIcon = {}); + Avatar(QUrl url, QIcon defaultIcon = {}); + Avatar(Avatar&&); ~Avatar(); + Avatar& operator=(Avatar&&); - using notifier_t = std::function<void()>; + using get_callback_t = std::function<void()>; + using upload_callback_t = std::function<void(QString)>; - QImage get(int dimension, notifier_t notifier) const; - QImage get(int w, int h, notifier_t notifier) const; + QImage get(Connection* connection, int dimension, + get_callback_t callback) const; + QImage get(Connection* connection, int w, int h, + get_callback_t callback) const; + + bool upload(Connection* connection, const QString& fileName, + upload_callback_t callback) const; + bool upload(Connection* connection, QIODevice* source, + upload_callback_t callback) const; QString mediaId() const; QUrl url() const; @@ -44,6 +56,6 @@ namespace QMatrixClient private: class Private; - QScopedPointer<Private> d; + std::unique_ptr<Private> d; }; } // namespace QMatrixClient @@ -64,7 +64,7 @@ class Room::Private Private(Connection* c, QString id_, JoinState initialJoinState) : q(nullptr), connection(c), id(std::move(id_)) - , avatar(c), joinState(initialJoinState) + , joinState(initialJoinState) { } Room* q; @@ -287,7 +287,7 @@ QImage Room::avatar(int dimension) QImage Room::avatar(int width, int height) { if (!d->avatar.url().isEmpty()) - return d->avatar.get(width, height, [=] { emit avatarChanged(); }); + return d->avatar.get(connection(), width, height, [=] { emit avatarChanged(); }); // Use the other side's avatar for 1:1's if (d->membersMap.size() == 2) @@ -295,8 +295,8 @@ QImage Room::avatar(int width, int height) auto theOtherOneIt = d->membersMap.begin(); if (theOtherOneIt.value() == localUser()) ++theOtherOneIt; - return (*theOtherOneIt)->avatarObject() - .get(width, height, [=] { emit avatarChanged(); }); + return (*theOtherOneIt)->avatar(width, height, + [=] { emit avatarChanged(); }); } return {}; } @@ -39,17 +39,15 @@ class User::Private public: Private(QString userId, Connection* connection) : userId(std::move(userId)), connection(connection) - , avatar(connection, QIcon::fromTheme(QStringLiteral("user-available"))) { } QString userId; QString name; QString bridged; Connection* connection; - Avatar avatar; - QPointer<UploadContentJob> avatarUploadJob = nullptr; + Avatar avatar { QIcon::fromTheme(QStringLiteral("user-available")) }; - void setAvatar(UploadContentJob* job, User* q); + void setAvatar(QString contentUri, User* q); }; User::User(QString userId, Connection* connection) @@ -107,28 +105,20 @@ void User::rename(const QString& newName) bool User::setAvatar(const QString& fileName) { - if (isJobRunning(d->avatarUploadJob)) - return false; - d->setAvatar(d->connection->uploadFile(fileName), this); - return true; + return avatarObject().upload(d->connection, fileName, + [this] (QString contentUri) { d->setAvatar(contentUri, this); }); } bool User::setAvatar(QIODevice* source) { - if (isJobRunning(d->avatarUploadJob) || !source->isReadable()) - return false; - d->setAvatar(d->connection->uploadContent(source), this); - return true; + return avatarObject().upload(d->connection, source, + [this] (QString contentUri) { d->setAvatar(contentUri, this); }); } -void User::Private::setAvatar(UploadContentJob* job, User* q) +void User::Private::setAvatar(QString contentUri, User* q) { - avatarUploadJob = job; - connect(job, &BaseJob::success, q, [this,q] { - auto* j = connection->callApi<SetAvatarUrlJob>( - userId, avatarUploadJob->contentUri()); - connect(j, &BaseJob::success, q, [q] { emit q->avatarChanged(q); }); - }); + auto* j = connection->callApi<SetAvatarUrlJob>(userId, contentUri); + connect(j, &BaseJob::success, q, [q] { emit q->avatarChanged(q); }); } QString User::displayname() const @@ -159,17 +149,23 @@ QImage User::avatar(int dimension) QImage User::avatar(int width, int height) { - return d->avatar.get(width, height, [=] { emit avatarChanged(this); }); + return avatar(width, height, []{}); +} + +QImage User::avatar(int width, int height, Avatar::get_callback_t callback) +{ + return avatarObject().get(d->connection, width, height, + [this,callback] { emit avatarChanged(this); callback(); }); } QString User::avatarMediaId() const { - return d->avatar.mediaId(); + return avatarObject().mediaId(); } QUrl User::avatarUrl() const { - return d->avatar.url(); + return avatarObject().url(); } void User::processEvent(Event* event) @@ -84,7 +84,8 @@ namespace QMatrixClient const Avatar& avatarObject() const; Q_INVOKABLE QImage avatar(int dimension); - Q_INVOKABLE QImage avatar(int requestedWidth, int requestedHeight); + Q_INVOKABLE QImage avatar(int width, int height); + QImage avatar(int width, int height, Avatar::get_callback_t callback); QString avatarMediaId() const; QUrl avatarUrl() const; |