diff options
author | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2017-11-29 23:39:35 +0200 |
---|---|---|
committer | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2017-11-29 23:39:35 +0200 |
commit | fdb76bb5c1bdce765479442a70ddca80b867caa6 (patch) | |
tree | b418ea31dbe0f140fc2635584666db4ce36bf732 /src | |
parent | b21942a3e3db3e425155c58483a99bc2789de241 (diff) |
Implement file uploads
fixes #24
Diffstat (limited to 'src')
-rw-r--r-- | src/ChatPage.cc | 11 | ||||
-rw-r--r-- | src/FileItem.cc | 47 | ||||
-rw-r--r-- | src/MatrixClient.cc | 60 | ||||
-rw-r--r-- | src/TextInputWidget.cc | 35 | ||||
-rw-r--r-- | src/TimelineItem.cc | 33 | ||||
-rw-r--r-- | src/TimelineView.cc | 27 | ||||
-rw-r--r-- | src/TimelineViewManager.cc | 19 |
7 files changed, 132 insertions, 100 deletions
diff --git a/src/ChatPage.cc b/src/ChatPage.cc index 82e694a1..5214d49a 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc @@ -187,6 +187,10 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent) client_->uploadImage(current_room_, filename); }); + connect(text_input_, &TextInputWidget::uploadFile, this, [=](QString filename) { + client_->uploadFile(current_room_, filename); + }); + connect(client_.data(), &MatrixClient::joinFailed, this, &ChatPage::showNotification); connect(client_.data(), &MatrixClient::imageUploaded, @@ -195,6 +199,13 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent) text_input_->hideUploadSpinner(); view_manager_->queueImageMessage(roomid, filename, url); }); + connect(client_.data(), + &MatrixClient::fileUploaded, + this, + [=](QString roomid, QString filename, QString url) { + text_input_->hideUploadSpinner(); + view_manager_->queueFileMessage(roomid, filename, url); + }); connect(client_.data(), SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)), diff --git a/src/FileItem.cc b/src/FileItem.cc index cd934783..96fd9c07 100644 --- a/src/FileItem.cc +++ b/src/FileItem.cc @@ -30,25 +30,16 @@ namespace events = matrix::events; namespace msgs = matrix::events::messages; -FileItem::FileItem(QSharedPointer<MatrixClient> client, - const events::MessageEvent<msgs::File> &event, - QWidget *parent) - : QWidget(parent) - , event_{event} - , client_{client} +void +FileItem::init() { setMouseTracking(true); setCursor(Qt::PointingHandCursor); setAttribute(Qt::WA_Hover, true); - url_ = event.msgContent().url(); - text_ = event.content().body(); - readableFileSize_ = calculateFileSize(event.msgContent().info().size); - icon_.addFile(":/icons/icons/ui/arrow-pointing-down.png"); QList<QString> url_parts = url_.toString().split("mxc://"); - if (url_parts.size() != 2) { qDebug() << "Invalid format for image" << url_.toString(); return; @@ -62,6 +53,20 @@ FileItem::FileItem(QSharedPointer<MatrixClient> client, } FileItem::FileItem(QSharedPointer<MatrixClient> client, + const events::MessageEvent<msgs::File> &event, + QWidget *parent) + : QWidget(parent) + , url_{event.msgContent().url()} + , text_{event.content().body()} + , event_{event} + , client_{client} +{ + readableFileSize_ = calculateFileSize(event.msgContent().info().size); + + init(); +} + +FileItem::FileItem(QSharedPointer<MatrixClient> client, const QString &url, const QString &filename, QWidget *parent) @@ -70,25 +75,9 @@ FileItem::FileItem(QSharedPointer<MatrixClient> client, , text_{QFileInfo(filename).fileName()} , client_{client} { - setMouseTracking(true); - setCursor(Qt::PointingHandCursor); - setAttribute(Qt::WA_Hover, true); - - // TODO: calculateFileSize - /* readableFileSize_ = calculateFileSize(event.msgContent().info().size); */ - - QList<QString> url_parts = url_.toString().split("mxc://"); - - icon_.addFile(":/icons/icons/ui/arrow-pointing-down.png"); + readableFileSize_ = calculateFileSize(QFileInfo(filename).size()); - if (url_parts.size() != 2) { - qDebug() << "Invalid format for image" << url_.toString(); - return; - } - - QString media_params = url_parts[1]; - url_ = QString("%1/_matrix/media/r0/download/%2") - .arg(client_.data()->getHomeServer().toString(), media_params); + init(); } QString diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc index a171cd09..66630c80 100644 --- a/src/MatrixClient.cc +++ b/src/MatrixClient.cc @@ -21,6 +21,7 @@ #include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> +#include <QMimeDatabase> #include <QNetworkReply> #include <QNetworkRequest> #include <QPixmap> @@ -287,6 +288,9 @@ MatrixClient::sendRoomMessage(matrix::events::MessageEventType ty, case matrix::events::MessageEventType::Image: body = {{"msgtype", "m.image"}, {"body", msg}, {"url", url}}; break; + case matrix::events::MessageEventType::File: + body = {{"msgtype", "m.file"}, {"body", msg}, {"url", url}}; + break; default: qDebug() << "SendRoomMessage: Unknown message type for" << msg; return; @@ -756,6 +760,62 @@ MatrixClient::uploadImage(const QString &roomid, const QString &filename) } void +MatrixClient::uploadFile(const QString &roomid, const QString &filename) +{ + QUrlQuery query; + query.addQueryItem("access_token", token_); + + QUrl endpoint(server_); + endpoint.setPath(mediaApiUrl_ + "/upload"); + endpoint.setQuery(query); + + QFile file(filename); + if (!file.open(QIODevice::ReadWrite)) { + qDebug() << "Error while reading" << filename; + return; + } + + QMimeDatabase db; + QMimeType mime = db.mimeTypeForFile(filename, QMimeDatabase::MatchContent); + + QNetworkRequest request(QString(endpoint.toEncoded())); + request.setHeader(QNetworkRequest::ContentLengthHeader, file.size()); + request.setHeader(QNetworkRequest::ContentTypeHeader, mime.name()); + + auto reply = post(request, file.readAll()); + connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, filename]() { + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (status == 0 || status >= 400) { + emit syncFailed(reply->errorString()); + return; + } + + auto data = reply->readAll(); + + if (data.isEmpty()) + return; + + auto json = QJsonDocument::fromJson(data); + + if (!json.isObject()) { + qDebug() << "Media upload: Response is not a json object."; + return; + } + + QJsonObject object = json.object(); + if (!object.contains("content_uri")) { + qDebug() << "Media upload: Missing content_uri key"; + qDebug() << object; + return; + } + + emit fileUploaded(roomid, filename, object.value("content_uri").toString()); + }); +} +void MatrixClient::joinRoom(const QString &roomIdOrAlias) { QUrlQuery query; diff --git a/src/TextInputWidget.cc b/src/TextInputWidget.cc index 829784fd..c4d01357 100644 --- a/src/TextInputWidget.cc +++ b/src/TextInputWidget.cc @@ -276,30 +276,27 @@ TextInputWidget::command(QString command, QString args) void TextInputWidget::openFileSelection() { - QStringList supportedFiles; - supportedFiles << "jpeg" - << "gif" - << "png" - << "bmp" - << "tiff" - << "webp"; - - auto fileName = QFileDialog::getOpenFileName( - this, - tr("Select an image"), - "", - tr("Image Files (*.bmp *.gif *.jpg *.jpeg *.png *.tiff *.webp)")); + QStringList imageExtensions; + imageExtensions << "jpeg" + << "gif" + << "png" + << "bmp" + << "tiff" + << "webp"; + + auto fileName = + QFileDialog::getOpenFileName(this, tr("Select an file"), "", tr("All Files (*)")); if (fileName.isEmpty()) return; - auto imageFormat = QString(QImageReader::imageFormat(fileName)); - if (!supportedFiles.contains(imageFormat)) { - qDebug() << "Unsupported image format for" << fileName; - return; - } + auto format = QString(QImageReader::imageFormat(fileName)); + + if (imageExtensions.contains(format)) + emit uploadImage(fileName); + else + emit uploadFile(fileName); - emit uploadImage(fileName); showUploadSpinner(); } diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc index b57f5118..7297abc3 100644 --- a/src/TimelineItem.cc +++ b/src/TimelineItem.cc @@ -15,20 +15,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <QDateTime> #include <QFontDatabase> #include <QRegExp> #include <QSettings> #include <QTextEdit> #include "Avatar.h" -#include "AvatarProvider.h" #include "Config.h" #include "FileItem.h" #include "ImageItem.h" #include "Sync.h" #include "TimelineItem.h" -#include "TimelineViewManager.h" static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)"); static const QString URL_HTML = "<a href=\"\\1\">\\1</a>"; @@ -119,29 +116,15 @@ TimelineItem::TimelineItem(ImageItem *image, { init(); - auto displayName = TimelineViewManager::displayName(userid); - auto timestamp = QDateTime::currentDateTime(); - - descriptionMsg_ = {"You", userid, " sent an image", descriptiveTime(timestamp)}; - - generateTimestamp(timestamp); - - auto imageLayout = new QHBoxLayout(); - imageLayout->setMargin(0); - imageLayout->addWidget(image); - imageLayout->addStretch(1); - - if (withSender) { - generateBody(displayName, ""); - setupAvatarLayout(displayName); - mainLayout_->addLayout(headerLayout_); + setupLocalWidgetLayout<ImageItem>(image, userid, "sent an image", withSender); +} - AvatarProvider::resolve(userid, this); - } else { - setupSimpleLayout(); - } +TimelineItem::TimelineItem(FileItem *file, const QString &userid, bool withSender, QWidget *parent) + : QWidget{parent} +{ + init(); - mainLayout_->addLayout(imageLayout); + setupLocalWidgetLayout<FileItem>(file, userid, "sent a file", withSender); } /* @@ -169,7 +152,7 @@ TimelineItem::TimelineItem(ImageItem *image, generateTimestamp(timestamp); auto imageLayout = new QHBoxLayout(); - imageLayout->setMargin(0); + imageLayout->setContentsMargins(0, 5, 0, 0); imageLayout->addWidget(image); imageLayout->addStretch(1); diff --git a/src/TimelineView.cc b/src/TimelineView.cc index bdc59af3..346ecc52 100644 --- a/src/TimelineView.cc +++ b/src/TimelineView.cc @@ -18,7 +18,6 @@ #include <QApplication> #include <QDebug> #include <QFileInfo> -#include <QSettings> #include <QTimer> #include "FileItem.h" @@ -27,7 +26,6 @@ #include "RoomMessages.h" #include "ScrollBar.h" #include "Sync.h" -#include "TimelineItem.h" #include "TimelineView.h" namespace events = matrix::events; @@ -570,30 +568,6 @@ TimelineView::addUserMessage(matrix::events::MessageEventType ty, const QString } void -TimelineView::addUserMessage(const QString &url, const QString &filename) -{ - QSettings settings; - auto user_id = settings.value("auth/user_id").toString(); - auto with_sender = lastSender_ != user_id; - - auto image = new ImageItem(client_, url, filename, this); - - TimelineItem *view_item = new TimelineItem(image, user_id, with_sender, scroll_widget_); - scroll_layout_->addWidget(view_item); - - lastMessageDirection_ = TimelineDirection::Bottom; - - QApplication::processEvents(); - - lastSender_ = user_id; - - int txn_id = client_->incrementTransactionId(); - PendingMessage message( - matrix::events::MessageEventType::Image, txn_id, url, filename, "", view_item); - handleNewUserMessage(message); -} - -void TimelineView::handleNewUserMessage(PendingMessage msg) { pending_msgs_.enqueue(msg); @@ -610,6 +584,7 @@ TimelineView::sendNextPendingMessage() PendingMessage &m = pending_msgs_.head(); switch (m.ty) { case matrix::events::MessageEventType::Image: + case matrix::events::MessageEventType::File: client_->sendRoomMessage( m.ty, m.txn_id, room_id_, QFileInfo(m.filename).fileName(), m.body); break; diff --git a/src/TimelineViewManager.cc b/src/TimelineViewManager.cc index 1f047d7c..daec481b 100644 --- a/src/TimelineViewManager.cc +++ b/src/TimelineViewManager.cc @@ -22,6 +22,8 @@ #include <QFileInfo> #include <QSettings> +#include "FileItem.h" +#include "ImageItem.h" #include "MatrixClient.h" #include "Sync.h" #include "TimelineView.h" @@ -92,7 +94,22 @@ TimelineViewManager::queueImageMessage(const QString &roomid, auto view = views_[roomid]; - view->addUserMessage(url, filename); + view->addUserMessage<ImageItem, matrix::events::MessageEventType::Image>(url, filename); +} + +void +TimelineViewManager::queueFileMessage(const QString &roomid, + const QString &filename, + const QString &url) +{ + if (!views_.contains(roomid)) { + qDebug() << "Cannot send m.file message to a non-managed view"; + return; + } + + auto view = views_[roomid]; + + view->addUserMessage<FileItem, matrix::events::MessageEventType::File>(url, filename); } void |