/* * nheko Copyright (C) 2017 Konstantinos Sideris * * This program 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. * * This program 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 this program. If not, see . */ #include "ui_ChatPage.h" #include #include #include #include #include #include #include "ChatPage.h" #include "Sync.h" #include "UserInfoWidget.h" ChatPage::ChatPage(QWidget *parent) : QWidget(parent) , ui(new Ui::ChatPage) , sync_interval_(2000) { ui->setupUi(this); matrix_client_ = new MatrixClient("matrix.org", parent); content_downloader_ = new QNetworkAccessManager(parent); room_list_ = new RoomList(this); top_bar_ = new TopRoomBar(this); ui->topBarLayout->addWidget(top_bar_); view_manager_ = new HistoryViewManager(this); ui->mainContentLayout->addWidget(view_manager_); text_input_ = new TextInputWidget(this); ui->contentLayout->addWidget(text_input_); user_info_widget_ = new UserInfoWidget(ui->sideBarTopWidget); sync_timer_ = new QTimer(this); connect(sync_timer_, SIGNAL(timeout()), this, SLOT(startSync())); connect(user_info_widget_, SIGNAL(logout()), matrix_client_, SLOT(logout())); connect(matrix_client_, SIGNAL(loggedOut()), this, SLOT(logout())); connect(room_list_, SIGNAL(roomChanged(const RoomInfo &)), this, SLOT(changeTopRoomInfo(const RoomInfo &))); connect(room_list_, SIGNAL(roomChanged(const RoomInfo &)), view_manager_, SLOT(setHistoryView(const RoomInfo &))); connect(room_list_, SIGNAL(fetchRoomAvatar(const QString &, const QUrl &)), this, SLOT(fetchRoomAvatar(const QString &, const QUrl &))); connect(text_input_, SIGNAL(sendTextMessage(const QString &)), this, SLOT(sendTextMessage(const QString &))); ui->sideBarTopUserInfoLayout->addWidget(user_info_widget_); ui->sideBarMainLayout->addWidget(room_list_); connect(matrix_client_, SIGNAL(initialSyncCompleted(SyncResponse)), this, SLOT(initialSyncCompleted(SyncResponse))); connect(matrix_client_, SIGNAL(syncCompleted(SyncResponse)), this, SLOT(syncCompleted(SyncResponse))); connect(matrix_client_, SIGNAL(getOwnProfileResponse(QUrl, QString)), this, SLOT(updateOwnProfileInfo(QUrl, QString))); connect(matrix_client_, SIGNAL(messageSent(QString, int)), this, SLOT(messageSent(QString, int))); } void ChatPage::logout() { sync_timer_->stop(); QSettings settings; settings.remove("auth/access_token"); settings.remove("auth/home_server"); settings.remove("auth/user_id"); settings.remove("client/transaction_id"); // Clear the environment. room_list_->clear(); view_manager_->clearAll(); top_bar_->reset(); user_info_widget_->reset(); matrix_client_->reset(); room_avatars_.clear(); emit close(); } void ChatPage::messageSent(QString event_id, int txn_id) { Q_UNUSED(event_id); QSettings settings; settings.setValue("client/transaction_id", txn_id + 1); } void ChatPage::sendTextMessage(const QString &msg) { auto room = current_room_; matrix_client_->sendTextMessage(current_room_.id(), msg); } void ChatPage::bootstrap(QString userid, QString homeserver, QString token) { Q_UNUSED(userid); matrix_client_->setServer(homeserver); matrix_client_->setAccessToken(token); matrix_client_->getOwnProfile(); matrix_client_->initialSync(); } void ChatPage::startSync() { matrix_client_->sync(); } void ChatPage::setOwnAvatar(const QByteArray &img) { if (img.size() == 0) return; QPixmap pixmap; pixmap.loadFromData(img); user_info_widget_->setAvatar(pixmap.toImage()); } void ChatPage::syncCompleted(const SyncResponse &response) { matrix_client_->setNextBatchToken(response.nextBatch()); /* room_list_->sync(response.rooms()); */ view_manager_->sync(response.rooms()); } void ChatPage::initialSyncCompleted(const SyncResponse &response) { if (!response.nextBatch().isEmpty()) matrix_client_->setNextBatchToken(response.nextBatch()); view_manager_->initialize(response.rooms()); room_list_->setInitialRooms(response.rooms()); sync_timer_->start(sync_interval_); } // TODO: This function should be part of the matrix client for generic media retrieval. void ChatPage::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url) { // TODO: move this into a Utils function QList url_parts = avatar_url.toString().split("mxc://"); if (url_parts.size() != 2) { qDebug() << "Invalid format for room avatar " << avatar_url.toString(); return; } QString media_params = url_parts[1]; QString media_url = QString("%1/_matrix/media/r0/download/%2") .arg(matrix_client_->getHomeServer(), media_params); QNetworkRequest avatar_request(media_url); QNetworkReply *reply = content_downloader_->get(avatar_request); reply->setProperty("media_params", media_params); connect(reply, &QNetworkReply::finished, [this, media_params, roomid, reply]() { reply->deleteLater(); auto media = reply->property("media_params").toString(); if (media != media_params) return; int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (status == 0) { qDebug() << reply->errorString(); return; } if (status >= 400) { qWarning() << "Request " << reply->request().url() << " returned " << status; return; } auto img = reply->readAll(); if (img.size() == 0) return; QPixmap pixmap; pixmap.loadFromData(img); room_avatars_.insert(roomid, pixmap); this->room_list_->updateRoomAvatar(roomid, pixmap.toImage()); if (current_room_.id() == roomid) { QIcon icon(pixmap); this->top_bar_->updateRoomAvatar(icon); } }); } void ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name) { QSettings settings; auto userid = settings.value("auth/user_id").toString(); user_info_widget_->setUserId(userid); user_info_widget_->setDisplayName(display_name); // TODO: move this into a Utils function QList url_parts = avatar_url.toString().split("mxc://"); if (url_parts.size() != 2) { qDebug() << "Invalid format for media " << avatar_url.toString(); return; } QString media_params = url_parts[1]; QString media_url = QString("%1/_matrix/media/r0/download/%2") .arg(matrix_client_->getHomeServer(), media_params); QNetworkRequest avatar_request(media_url); QNetworkReply *reply = content_downloader_->get(avatar_request); reply->setProperty("media_params", media_params); connect(reply, &QNetworkReply::finished, [this, media_params, reply]() { reply->deleteLater(); auto media = reply->property("media_params").toString(); if (media != media_params) return; int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (status == 0) { qDebug() << reply->errorString(); return; } if (status >= 400) { qWarning() << "Request " << reply->request().url() << " returned " << status; return; } setOwnAvatar(reply->readAll()); }); } void ChatPage::changeTopRoomInfo(const RoomInfo &info) { top_bar_->updateRoomName(info.name()); top_bar_->updateRoomTopic(info.topic()); if (room_avatars_.contains(info.id())) { QIcon icon(room_avatars_.value(info.id())); top_bar_->updateRoomAvatar(icon); } current_room_ = info; } ChatPage::~ChatPage() { sync_timer_->stop(); delete ui; }