Use only a MatrixClient as a shared pointer

This commit is contained in:
Konstantinos Sideris 2017-04-11 17:45:47 +03:00
parent 0770f6e6b5
commit 6468faa39e
15 changed files with 214 additions and 220 deletions

View file

@ -47,7 +47,14 @@ SET(PROJECT_VERSION ${CPACK_PACKAGE_VERSION})
MESSAGE(STATUS "Version: ${PROJECT_VERSION}") MESSAGE(STATUS "Version: ${PROJECT_VERSION}")
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -Wextra -Werror -pedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
-std=gnu++11 \
-Wall \
-Wextra \
-Werror \
-fdiagnostics-color=always \
-pedantic \
-Wunreachable-code")
endif() endif()
set(SRC_FILES set(SRC_FILES
@ -104,7 +111,6 @@ qt5_wrap_cpp(MOC_HEADERS
include/LoginPage.h include/LoginPage.h
include/MainWindow.h include/MainWindow.h
include/MatrixClient.h include/MatrixClient.h
include/Register.h
include/RegisterPage.h include/RegisterPage.h
include/RoomInfoListItem.h include/RoomInfoListItem.h
include/RoomList.h include/RoomList.h

View file

@ -1,13 +1,13 @@
run: debug
./build/nheko
debug: debug:
@cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug @cmake -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug
@make -C build -j2 @cmake --build build
release-debug: release-debug:
@cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo @cmake -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
@make -C build -j2 @cmake --build build
run:
@./build/nheko
clean: clean:
rm -rf build rm -rf build

View file

@ -42,7 +42,7 @@ class ChatPage : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ChatPage(QWidget *parent = 0); ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~ChatPage(); ~ChatPage();
// Initialize all the components of the UI. // Initialize all the components of the UI.
@ -51,10 +51,10 @@ public:
signals: signals:
void close(); void close();
public slots: private slots:
// Updates the user info box. void updateTopBarAvatar(const QString &roomid, const QPixmap &img);
void updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name); void updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name);
void fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url); void setOwnAvatar(const QPixmap &img);
void initialSyncCompleted(const SyncResponse &response); void initialSyncCompleted(const SyncResponse &response);
void syncCompleted(const SyncResponse &response); void syncCompleted(const SyncResponse &response);
void syncFailed(const QString &msg); void syncFailed(const QString &msg);
@ -67,8 +67,6 @@ public slots:
private: private:
Ui::ChatPage *ui; Ui::ChatPage *ui;
void setOwnAvatar(const QByteArray &img);
RoomList *room_list_; RoomList *room_list_;
HistoryViewManager *view_manager_; HistoryViewManager *view_manager_;
@ -83,11 +81,8 @@ private:
UserInfoWidget *user_info_widget_; UserInfoWidget *user_info_widget_;
// Matrix client // Matrix Client API provider.
MatrixClient *matrix_client_; QSharedPointer<MatrixClient> client_;
// Used for one off media requests.
QNetworkAccessManager *content_downloader_;
}; };
#endif // CHATPAGE_H #endif // CHATPAGE_H

View file

@ -20,11 +20,13 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QSharedPointer>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QWidget> #include <QWidget>
#include "FlatButton.h" #include "FlatButton.h"
#include "InputValidator.h" #include "InputValidator.h"
#include "MatrixClient.h"
#include "RaisedButton.h" #include "RaisedButton.h"
#include "TextField.h" #include "TextField.h"
@ -33,7 +35,7 @@ class LoginPage : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit LoginPage(QWidget *parent = 0); LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~LoginPage(); ~LoginPage();
void reset(); void reset();
@ -41,14 +43,6 @@ public:
signals: signals:
void backButtonClicked(); void backButtonClicked();
// Emitted after the matrix ID validation. The handler should be
// responsible for performing the actual login with a remote server.
void userLogin(const QString &username, const QString &password, const QString home_server);
public slots:
// Displays errors produced during the login.
void loginError(QString error_message);
private slots: private slots:
// Callback for the back button. // Callback for the back button.
void onBackButtonClicked(); void onBackButtonClicked();
@ -56,6 +50,9 @@ private slots:
// Callback for the login button. // Callback for the login button.
void onLoginButtonClicked(); void onLoginButtonClicked();
// Displays errors produced during the login.
void loginError(QString error_message);
private: private:
QVBoxLayout *top_layout_; QVBoxLayout *top_layout_;
@ -77,6 +74,9 @@ private:
TextField *password_input_; TextField *password_input_;
InputValidator *matrix_id_validator_; InputValidator *matrix_id_validator_;
// Matrix client API provider.
QSharedPointer<MatrixClient> client_;
}; };
#endif // LOGINPAGE_H #endif // LOGINPAGE_H

View file

@ -19,6 +19,7 @@
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <QMainWindow>
#include <QSharedPointer>
#include "ChatPage.h" #include "ChatPage.h"
#include "LoginPage.h" #include "LoginPage.h"
@ -53,12 +54,6 @@ public slots:
// Show the chat page and start communicating with the given access token. // Show the chat page and start communicating with the given access token.
void showChatPage(QString user_id, QString home_server, QString token); void showChatPage(QString user_id, QString home_server, QString token);
// Performs the actual login.
void matrixLogin(const QString &username, const QString &password, const QString &home_server);
// Performs the actual registration.
void matrixRegister(const QString &username, const QString &password, const QString &server);
private: private:
// The UI component of the main window. // The UI component of the main window.
Ui::MainWindow *ui_; Ui::MainWindow *ui_;
@ -78,7 +73,8 @@ private:
// The main chat area. // The main chat area.
ChatPage *chat_page_; ChatPage *chat_page_;
MatrixClient *matrix_client_; // Matrix Client API provider.
QSharedPointer<MatrixClient> client_;
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View file

@ -40,6 +40,8 @@ public:
void login(const QString &username, const QString &password) noexcept; void login(const QString &username, const QString &password) noexcept;
void registerUser(const QString &username, const QString &password, const QString &server) noexcept; void registerUser(const QString &username, const QString &password, const QString &server) noexcept;
void versions() noexcept; void versions() noexcept;
void fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url);
void fetchOwnAvatar(const QUrl &avatar_url);
inline QString getHomeServer(); inline QString getHomeServer();
inline void incrementTransactionId(); inline void incrementTransactionId();
@ -63,6 +65,9 @@ signals:
void loginSuccess(const QString &userid, const QString &homeserver, const QString &token); void loginSuccess(const QString &userid, const QString &homeserver, const QString &token);
void registerSuccess(const QString &userid, const QString &homeserver, const QString &token); void registerSuccess(const QString &userid, const QString &homeserver, const QString &token);
void roomAvatarRetrieved(const QString &roomid, const QPixmap &img);
void ownAvatarRetrieved(const QPixmap &img);
// Returned profile data for the user's account. // Returned profile data for the user's account.
void getOwnProfileResponse(const QUrl &avatar_url, const QString &display_name); void getOwnProfileResponse(const QUrl &avatar_url, const QString &display_name);
void initialSyncCompleted(const SyncResponse &response); void initialSyncCompleted(const SyncResponse &response);
@ -76,11 +81,13 @@ private slots:
private: private:
enum Endpoint { enum Endpoint {
GetOwnProfile, GetOwnProfile,
GetOwnAvatar,
GetProfile, GetProfile,
InitialSync, InitialSync,
Login, Login,
Logout, Logout,
Register, Register,
RoomAvatar,
SendTextMessage, SendTextMessage,
Sync, Sync,
Versions, Versions,
@ -92,9 +99,11 @@ private:
void onRegisterResponse(QNetworkReply *reply); void onRegisterResponse(QNetworkReply *reply);
void onVersionsResponse(QNetworkReply *reply); void onVersionsResponse(QNetworkReply *reply);
void onGetOwnProfileResponse(QNetworkReply *reply); void onGetOwnProfileResponse(QNetworkReply *reply);
void onGetOwnAvatarResponse(QNetworkReply *reply);
void onSendTextMessageResponse(QNetworkReply *reply); void onSendTextMessageResponse(QNetworkReply *reply);
void onInitialSyncResponse(QNetworkReply *reply); void onInitialSyncResponse(QNetworkReply *reply);
void onSyncResponse(QNetworkReply *reply); void onSyncResponse(QNetworkReply *reply);
void onRoomAvatarResponse(QNetworkReply *reply);
// Client API prefix. // Client API prefix.
QString api_url_; QString api_url_;

View file

@ -20,11 +20,13 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QSharedPointer>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QWidget> #include <QWidget>
#include "FlatButton.h" #include "FlatButton.h"
#include "InputValidator.h" #include "InputValidator.h"
#include "MatrixClient.h"
#include "RaisedButton.h" #include "RaisedButton.h"
#include "TextField.h" #include "TextField.h"
@ -33,24 +35,19 @@ class RegisterPage : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit RegisterPage(QWidget *parent = 0); RegisterPage(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~RegisterPage(); ~RegisterPage();
signals: signals:
void backButtonClicked(); void backButtonClicked();
// Emitted after successful input validation. The handler should be
// responsible for the actual registering on the remote Matrix server.
void registerUser(const QString &username, const QString &password, const QString &server);
public slots:
// Display registration specific errors to the user.
void registerError(const QString &msg);
private slots: private slots:
void onBackButtonClicked(); void onBackButtonClicked();
void onRegisterButtonClicked(); void onRegisterButtonClicked();
// Display registration specific errors to the user.
void registerError(const QString &msg);
private: private:
QVBoxLayout *top_layout_; QVBoxLayout *top_layout_;
@ -74,6 +71,9 @@ private:
TextField *server_input_; TextField *server_input_;
InputValidator *validator_; InputValidator *validator_;
// Matrix client API provider.
QSharedPointer<MatrixClient> client_;
}; };
#endif // REGISTERPAGE_H #endif // REGISTERPAGE_H

View file

@ -19,9 +19,11 @@
#define ROOMLIST_H #define ROOMLIST_H
#include <QImage> #include <QImage>
#include <QSharedPointer>
#include <QUrl> #include <QUrl>
#include <QWidget> #include <QWidget>
#include "MatrixClient.h"
#include "RoomInfo.h" #include "RoomInfo.h"
#include "RoomInfoListItem.h" #include "RoomInfoListItem.h"
#include "Sync.h" #include "Sync.h"
@ -36,26 +38,27 @@ class RoomList : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit RoomList(QWidget *parent = 0); RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
~RoomList(); ~RoomList();
void setInitialRooms(const Rooms &rooms); void setInitialRooms(const Rooms &rooms);
void updateRoomAvatar(const QString &roomid, const QImage &avatar_image);
void clear(); void clear();
RoomInfo extractRoomInfo(const State &room_state); RoomInfo extractRoomInfo(const State &room_state);
signals: signals:
void roomChanged(const RoomInfo &info); void roomChanged(const RoomInfo &info);
void fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url);
public slots: public slots:
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
void highlightSelectedRoom(const RoomInfo &info); void highlightSelectedRoom(const RoomInfo &info);
private: private:
Ui::RoomList *ui; Ui::RoomList *ui;
QMap<QString, RoomInfoListItem *> rooms_; QMap<QString, RoomInfoListItem *> rooms_;
QSharedPointer<MatrixClient> client_;
}; };
#endif // ROOMLIST_H #endif // ROOMLIST_H

View file

@ -28,16 +28,15 @@
#include "Sync.h" #include "Sync.h"
#include "UserInfoWidget.h" #include "UserInfoWidget.h"
ChatPage::ChatPage(QWidget *parent) ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::ChatPage) , ui(new Ui::ChatPage)
, sync_interval_(2000) , sync_interval_(2000)
, client_(client)
{ {
ui->setupUi(this); ui->setupUi(this);
matrix_client_ = new MatrixClient("matrix.org", parent);
content_downloader_ = new QNetworkAccessManager(parent);
room_list_ = new RoomList(this); room_list_ = new RoomList(client, this);
ui->sideBarMainLayout->addWidget(room_list_); ui->sideBarMainLayout->addWidget(room_list_);
top_bar_ = new TopRoomBar(this); top_bar_ = new TopRoomBar(this);
@ -56,8 +55,8 @@ ChatPage::ChatPage(QWidget *parent)
sync_timer_->setSingleShot(true); sync_timer_->setSingleShot(true);
connect(sync_timer_, SIGNAL(timeout()), this, SLOT(startSync())); connect(sync_timer_, SIGNAL(timeout()), this, SLOT(startSync()));
connect(user_info_widget_, SIGNAL(logout()), matrix_client_, SLOT(logout())); connect(user_info_widget_, SIGNAL(logout()), client_.data(), SLOT(logout()));
connect(matrix_client_, SIGNAL(loggedOut()), this, SLOT(logout())); connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout()));
connect(room_list_, connect(room_list_,
SIGNAL(roomChanged(const RoomInfo &)), SIGNAL(roomChanged(const RoomInfo &)),
@ -67,33 +66,38 @@ ChatPage::ChatPage(QWidget *parent)
SIGNAL(roomChanged(const RoomInfo &)), SIGNAL(roomChanged(const RoomInfo &)),
view_manager_, view_manager_,
SLOT(setHistoryView(const RoomInfo &))); SLOT(setHistoryView(const RoomInfo &)));
connect(room_list_,
SIGNAL(fetchRoomAvatar(const QString &, const QUrl &)),
this,
SLOT(fetchRoomAvatar(const QString &, const QUrl &)));
connect(text_input_, connect(text_input_,
SIGNAL(sendTextMessage(const QString &)), SIGNAL(sendTextMessage(const QString &)),
this, this,
SLOT(sendTextMessage(const QString &))); SLOT(sendTextMessage(const QString &)));
connect(matrix_client_, connect(client_.data(),
SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)),
this,
SLOT(updateTopBarAvatar(const QString &, const QPixmap &)));
connect(client_.data(),
SIGNAL(initialSyncCompleted(const SyncResponse &)), SIGNAL(initialSyncCompleted(const SyncResponse &)),
this, this,
SLOT(initialSyncCompleted(const SyncResponse &))); SLOT(initialSyncCompleted(const SyncResponse &)));
connect(matrix_client_, connect(client_.data(),
SIGNAL(syncCompleted(const SyncResponse &)), SIGNAL(syncCompleted(const SyncResponse &)),
this, this,
SLOT(syncCompleted(const SyncResponse &))); SLOT(syncCompleted(const SyncResponse &)));
connect(matrix_client_, connect(client_.data(),
SIGNAL(syncFailed(const QString &)), SIGNAL(syncFailed(const QString &)),
this, this,
SLOT(syncFailed(const QString &))); SLOT(syncFailed(const QString &)));
connect(matrix_client_, connect(client_.data(),
SIGNAL(getOwnProfileResponse(const QUrl &, const QString &)), SIGNAL(getOwnProfileResponse(const QUrl &, const QString &)),
this, this,
SLOT(updateOwnProfileInfo(const QUrl &, const QString &))); SLOT(updateOwnProfileInfo(const QUrl &, const QString &)));
connect(matrix_client_, connect(client_.data(),
SIGNAL(ownAvatarRetrieved(const QPixmap &)),
this,
SLOT(setOwnAvatar(const QPixmap &)));
connect(client_.data(),
SIGNAL(messageSent(QString, int)), SIGNAL(messageSent(QString, int)),
this, this,
SLOT(messageSent(QString, int))); SLOT(messageSent(QString, int)));
@ -115,7 +119,7 @@ void ChatPage::logout()
top_bar_->reset(); top_bar_->reset();
user_info_widget_->reset(); user_info_widget_->reset();
matrix_client_->reset(); client_->reset();
room_avatars_.clear(); room_avatars_.clear();
@ -133,33 +137,28 @@ void ChatPage::messageSent(QString event_id, int txn_id)
void ChatPage::sendTextMessage(const QString &msg) void ChatPage::sendTextMessage(const QString &msg)
{ {
auto room = current_room_; auto room = current_room_;
matrix_client_->sendTextMessage(current_room_.id(), msg); client_->sendTextMessage(current_room_.id(), msg);
} }
void ChatPage::bootstrap(QString userid, QString homeserver, QString token) void ChatPage::bootstrap(QString userid, QString homeserver, QString token)
{ {
Q_UNUSED(userid); Q_UNUSED(userid);
matrix_client_->setServer(homeserver); client_->setServer(homeserver);
matrix_client_->setAccessToken(token); client_->setAccessToken(token);
matrix_client_->getOwnProfile(); client_->getOwnProfile();
matrix_client_->initialSync(); client_->initialSync();
} }
void ChatPage::startSync() void ChatPage::startSync()
{ {
matrix_client_->sync(); client_->sync();
} }
void ChatPage::setOwnAvatar(const QByteArray &img) void ChatPage::setOwnAvatar(const QPixmap &img)
{ {
if (img.size() == 0) user_info_widget_->setAvatar(img.toImage());
return;
QPixmap pixmap;
pixmap.loadFromData(img);
user_info_widget_->setAvatar(pixmap.toImage());
} }
void ChatPage::syncFailed(const QString &msg) void ChatPage::syncFailed(const QString &msg)
@ -170,7 +169,7 @@ void ChatPage::syncFailed(const QString &msg)
void ChatPage::syncCompleted(const SyncResponse &response) void ChatPage::syncCompleted(const SyncResponse &response)
{ {
matrix_client_->setNextBatchToken(response.nextBatch()); client_->setNextBatchToken(response.nextBatch());
/* room_list_->sync(response.rooms()); */ /* room_list_->sync(response.rooms()); */
view_manager_->sync(response.rooms()); view_manager_->sync(response.rooms());
@ -181,7 +180,7 @@ void ChatPage::syncCompleted(const SyncResponse &response)
void ChatPage::initialSyncCompleted(const SyncResponse &response) void ChatPage::initialSyncCompleted(const SyncResponse &response)
{ {
if (!response.nextBatch().isEmpty()) if (!response.nextBatch().isEmpty())
matrix_client_->setNextBatchToken(response.nextBatch()); client_->setNextBatchToken(response.nextBatch());
view_manager_->initialize(response.rooms()); view_manager_->initialize(response.rooms());
room_list_->setInitialRooms(response.rooms()); room_list_->setInitialRooms(response.rooms());
@ -189,62 +188,16 @@ void ChatPage::initialSyncCompleted(const SyncResponse &response)
sync_timer_->start(sync_interval_); sync_timer_->start(sync_interval_);
} }
// TODO: This function should be part of the matrix client for generic media retrieval. void ChatPage::updateTopBarAvatar(const QString &roomid, const QPixmap &img)
void ChatPage::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url)
{ {
// TODO: move this into a Utils function room_avatars_.insert(roomid, img);
QList<QString> url_parts = avatar_url.toString().split("mxc://");
if (url_parts.size() != 2) { if (current_room_.id() != roomid)
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; return;
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QIcon icon(img);
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); this->top_bar_->updateRoomAvatar(icon);
} }
});
}
void ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name) void ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name)
{ {
@ -254,44 +207,7 @@ void ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &displ
user_info_widget_->setUserId(userid); user_info_widget_->setUserId(userid);
user_info_widget_->setDisplayName(display_name); user_info_widget_->setDisplayName(display_name);
// TODO: move this into a Utils function client_->fetchOwnAvatar(avatar_url);
QList<QString> 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) void ChatPage::changeTopRoomInfo(const RoomInfo &info)

View file

@ -19,10 +19,12 @@
#include "LoginPage.h" #include "LoginPage.h"
LoginPage::LoginPage(QWidget *parent) LoginPage::LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, matrix_id_validator_(new InputValidator(parent)) , client_(client)
{ {
matrix_id_validator_ = new InputValidator(this);
top_layout_ = new QVBoxLayout(); top_layout_ = new QVBoxLayout();
back_layout_ = new QHBoxLayout(); back_layout_ = new QHBoxLayout();
@ -105,19 +107,19 @@ LoginPage::LoginPage(QWidget *parent)
top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter); top_layout_->addWidget(error_label_, 0, Qt::AlignHCenter);
top_layout_->addStretch(1); top_layout_->addStretch(1);
setLayout(top_layout_);
connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked())); connect(back_button_, SIGNAL(clicked()), this, SLOT(onBackButtonClicked()));
connect(login_button_, SIGNAL(clicked()), this, SLOT(onLoginButtonClicked())); connect(login_button_, SIGNAL(clicked()), this, SLOT(onLoginButtonClicked()));
connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click())); connect(matrixid_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click())); connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(client_.data(), SIGNAL(loginError(QString)), this, SLOT(loginError(QString)));
matrixid_input_->setValidator(matrix_id_validator_->id_); matrixid_input_->setValidator(matrix_id_validator_->id_);
setLayout(top_layout_);
} }
void LoginPage::loginError(QString error) void LoginPage::loginError(QString error)
{ {
qWarning() << "Error Message: " << error;
error_label_->setText(error); error_label_->setText(error);
} }
@ -134,7 +136,8 @@ void LoginPage::onLoginButtonClicked()
QString home_server = matrixid_input_->text().split(":").at(1); QString home_server = matrixid_input_->text().split(":").at(1);
QString password = password_input_->text(); QString password = password_input_->text();
emit userLogin(user, password, home_server); client_->setServer(home_server);
client_->login(user, password);
} }
} }

View file

@ -25,13 +25,15 @@
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui_(new Ui::MainWindow) , ui_(new Ui::MainWindow)
, welcome_page_(new WelcomePage(parent))
, login_page_(new LoginPage(parent))
, register_page_(new RegisterPage(parent))
, chat_page_(new ChatPage(parent))
, matrix_client_(new MatrixClient("matrix.org", parent))
{ {
ui_->setupUi(this); ui_->setupUi(this);
client_ = QSharedPointer<MatrixClient>(new MatrixClient("matrix.org"));
welcome_page_ = new WelcomePage(this);
login_page_ = new LoginPage(client_, this);
register_page_ = new RegisterPage(client_, this);
chat_page_ = new ChatPage(client_, this);
// Initialize sliding widget manager. // Initialize sliding widget manager.
sliding_stack_ = new SlidingStackWidget(this); sliding_stack_ = new SlidingStackWidget(this);
@ -46,39 +48,16 @@ MainWindow::MainWindow(QWidget *parent)
connect(welcome_page_, SIGNAL(userRegister()), this, SLOT(showRegisterPage())); connect(welcome_page_, SIGNAL(userRegister()), this, SLOT(showRegisterPage()));
connect(login_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage())); connect(login_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
connect(login_page_,
SIGNAL(userLogin(const QString &, const QString &, const QString &)),
this,
SLOT(matrixLogin(const QString &, const QString &, const QString &)));
connect(register_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage())); connect(register_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
connect(register_page_,
SIGNAL(registerUser(const QString &, const QString &, const QString &)),
this,
SLOT(matrixRegister(const QString &, const QString &, const QString &)));
connect(chat_page_, SIGNAL(close()), this, SLOT(showWelcomePage())); connect(chat_page_, SIGNAL(close()), this, SLOT(showWelcomePage()));
connect(matrix_client_, connect(client_.data(),
SIGNAL(registerError(const QString &)),
register_page_,
SLOT(registerError(const QString &)));
connect(matrix_client_, SIGNAL(loginError(QString)), login_page_, SLOT(loginError(QString)));
connect(matrix_client_,
SIGNAL(loginSuccess(QString, QString, QString)), SIGNAL(loginSuccess(QString, QString, QString)),
this, this,
SLOT(showChatPage(QString, QString, QString))); SLOT(showChatPage(QString, QString, QString)));
} }
void MainWindow::matrixLogin(const QString &username, const QString &password, const QString &home_server)
{
qDebug() << "Logging in..." << username;
matrix_client_->setServer(home_server);
matrix_client_->login(username, password);
}
void MainWindow::showChatPage(QString userid, QString homeserver, QString token) void MainWindow::showChatPage(QString userid, QString homeserver, QString token)
{ {
QSettings settings; QSettings settings;
@ -93,12 +72,6 @@ void MainWindow::showChatPage(QString userid, QString homeserver, QString token)
chat_page_->bootstrap(userid, homeserver, token); chat_page_->bootstrap(userid, homeserver, token);
} }
void MainWindow::matrixRegister(const QString &username, const QString &password, const QString &server)
{
qDebug() << "Registering" << username << "at" << server;
matrix_client_->registerUser(username, password, server);
}
void MainWindow::showWelcomePage() void MainWindow::showWelcomePage()
{ {
int index = sliding_stack_->getWidgetIndex(welcome_page_); int index = sliding_stack_->getWidgetIndex(welcome_page_);

View file

@ -20,6 +20,7 @@
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QPixmap>
#include <QSettings> #include <QSettings>
#include <QUrl> #include <QUrl>
#include <QUrlQuery> #include <QUrlQuery>
@ -39,7 +40,6 @@ MatrixClient::MatrixClient(QString server, QObject *parent)
QSettings settings; QSettings settings;
txn_id_ = settings.value("client/transaction_id", 1).toInt(); txn_id_ = settings.value("client/transaction_id", 1).toInt();
// FIXME: Other QNetworkAccessManagers use the finish handler.
connect(this, SIGNAL(finished(QNetworkReply *)), this, SLOT(onResponse(QNetworkReply *))); connect(this, SIGNAL(finished(QNetworkReply *)), this, SLOT(onResponse(QNetworkReply *)));
} }
@ -263,6 +263,52 @@ void MatrixClient::onSendTextMessageResponse(QNetworkReply *reply)
incrementTransactionId(); incrementTransactionId();
} }
void MatrixClient::onRoomAvatarResponse(QNetworkReply *reply)
{
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (status == 0 || status >= 400) {
qWarning() << reply->errorString();
return;
}
auto img = reply->readAll();
if (img.size() == 0)
return;
auto roomid = reply->property("roomid").toString();
QPixmap pixmap;
pixmap.loadFromData(img);
emit roomAvatarRetrieved(roomid, pixmap);
}
void MatrixClient::onGetOwnAvatarResponse(QNetworkReply *reply)
{
reply->deleteLater();
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (status == 0 || status >= 400) {
qWarning() << reply->errorString();
return;
}
auto img = reply->readAll();
if (img.size() == 0)
return;
QPixmap pixmap;
pixmap.loadFromData(img);
emit ownAvatarRetrieved(pixmap);
}
void MatrixClient::onResponse(QNetworkReply *reply) void MatrixClient::onResponse(QNetworkReply *reply)
{ {
switch (reply->property("endpoint").toInt()) { switch (reply->property("endpoint").toInt()) {
@ -290,6 +336,12 @@ void MatrixClient::onResponse(QNetworkReply *reply)
case Endpoint::SendTextMessage: case Endpoint::SendTextMessage:
onSendTextMessageResponse(reply); onSendTextMessageResponse(reply);
break; break;
case Endpoint::RoomAvatar:
onRoomAvatarResponse(reply);
break;
case Endpoint::GetOwnAvatar:
onGetOwnAvatarResponse(reply);
break;
default: default:
break; break;
} }
@ -448,3 +500,40 @@ void MatrixClient::getOwnProfile() noexcept
QNetworkReply *reply = get(request); QNetworkReply *reply = get(request);
reply->setProperty("endpoint", Endpoint::GetOwnProfile); reply->setProperty("endpoint", Endpoint::GetOwnProfile);
} }
void MatrixClient::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url)
{
QList<QString> 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(getHomeServer(), media_params);
QNetworkRequest avatar_request(media_url);
QNetworkReply *reply = get(avatar_request);
reply->setProperty("roomid", roomid);
reply->setProperty("endpoint", Endpoint::RoomAvatar);
}
void MatrixClient::fetchOwnAvatar(const QUrl &avatar_url)
{
QList<QString> 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(getHomeServer(), media_params);
QNetworkRequest avatar_request(media_url);
QNetworkReply *reply = get(avatar_request);
reply->setProperty("endpoint", Endpoint::GetOwnAvatar);
}

View file

@ -22,10 +22,6 @@
#include "Deserializable.h" #include "Deserializable.h"
#include "Register.h" #include "Register.h"
RegisterRequest::RegisterRequest()
{
}
RegisterRequest::RegisterRequest(const QString &username, const QString &password) RegisterRequest::RegisterRequest(const QString &username, const QString &password)
: user_(username) : user_(username)
, password_(password) , password_(password)

View file

@ -20,9 +20,10 @@
#include "RegisterPage.h" #include "RegisterPage.h"
RegisterPage::RegisterPage(QWidget *parent) RegisterPage::RegisterPage(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, validator_(new InputValidator(parent)) , validator_(new InputValidator(parent))
, client_(client)
{ {
top_layout_ = new QVBoxLayout(); top_layout_ = new QVBoxLayout();
@ -125,6 +126,7 @@ RegisterPage::RegisterPage(QWidget *parent)
connect(password_input_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(password_input_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(password_confirmation_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(password_confirmation_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(server_input_, SIGNAL(returnPressed()), register_button_, SLOT(click())); connect(server_input_, SIGNAL(returnPressed()), register_button_, SLOT(click()));
connect(client_.data(), SIGNAL(registerError(const QString &)), this, SLOT(registerError(const QString &)));
username_input_->setValidator(validator_->localpart_); username_input_->setValidator(validator_->localpart_);
password_input_->setValidator(validator_->password_); password_input_->setValidator(validator_->password_);
@ -160,7 +162,7 @@ void RegisterPage::onRegisterButtonClicked()
QString password = password_input_->text(); QString password = password_input_->text();
QString server = server_input_->text(); QString server = server_input_->text();
emit registerUser(username, password, server); client_->registerUser(username, password, server);
} }
} }

View file

@ -26,12 +26,18 @@
#include "RoomList.h" #include "RoomList.h"
#include "Sync.h" #include "Sync.h"
RoomList::RoomList(QWidget *parent) RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::RoomList) , ui(new Ui::RoomList)
, client_(client)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->scrollVerticalLayout->addStretch(1); ui->scrollVerticalLayout->addStretch(1);
connect(client_.data(),
SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)),
this,
SLOT(updateRoomAvatar(const QString &, const QPixmap &)));
} }
RoomList::~RoomList() RoomList::~RoomList()
@ -85,7 +91,7 @@ void RoomList::setInitialRooms(const Rooms &rooms)
continue; continue;
if (!info.avatarUrl().isEmpty()) if (!info.avatarUrl().isEmpty())
emit fetchRoomAvatar(info.id(), info.avatarUrl()); client_->fetchRoomAvatar(info.id(), info.avatarUrl());
RoomInfoListItem *room_item = new RoomInfoListItem(info, ui->scrollArea); RoomInfoListItem *room_item = new RoomInfoListItem(info, ui->scrollArea);
connect(room_item, connect(room_item,
@ -115,7 +121,7 @@ void RoomList::highlightSelectedRoom(const RoomInfo &info)
} }
} }
void RoomList::updateRoomAvatar(const QString &roomid, const QImage &avatar_image) void RoomList::updateRoomAvatar(const QString &roomid, const QPixmap &img)
{ {
if (!rooms_.contains(roomid)) { if (!rooms_.contains(roomid)) {
qDebug() << "Avatar update on non existent room" << roomid; qDebug() << "Avatar update on non existent room" << roomid;
@ -123,5 +129,5 @@ void RoomList::updateRoomAvatar(const QString &roomid, const QImage &avatar_imag
} }
auto list_item = rooms_.value(roomid); auto list_item = rooms_.value(roomid);
list_item->setAvatar(avatar_image); list_item->setAvatar(img.toImage());
} }