Fix crashing when logging out.

That's a complex issue. Yay!
This commit is contained in:
Black Hat 2018-09-09 21:13:43 +08:00
parent 7c426e254b
commit 5c55856df3
8 changed files with 105 additions and 132 deletions

View File

@ -2,70 +2,37 @@ import QtQuick 2.9
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2 import QtQuick.Controls.Material 2.2
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.3
import Matrique 0.1
import Matrique.Settings 0.1 import Matrique.Settings 0.1
import "component" import "component"
import "form" import "form"
Page { Page {
// Page { property alias listModel: accountSettingsListView.model
// id: accountForm Page {
// parent: null
// padding: 64
// ColumnLayout {
// RowLayout {
// Layout.preferredHeight: 60
// ImageStatus {
// Layout.preferredWidth: height
// Layout.fillHeight: true
// source: matriqueController.isLogin ? connection.localUser && connection.localUser.avatarUrl ? "image://mxc/" + connection.localUser.avatarUrl : "" : "qrc:/asset/img/avatar.png"
// displayText: matriqueController.isLogin && connection.localUser.displayName ? connection.localUser.displayName : ""
// }
// ColumnLayout {
// Layout.fillWidth: true
// Layout.fillHeight: true
// Label {
// font.pointSize: 18
// text: matriqueController.isLogin ? connection.localUser.displayName : ""
// }
// Label {
// font.pointSize: 12
// text: matriqueController.isLogin ? connection.localUser.id : ""
// }
// }
// }
// Button {
// text: "Logout"
// highlighted: true
// onClicked: {
// matriqueController.logout()
// Qt.quit()
// }
// }
// }
// }
Page{
id: accountForm id: accountForm
parent: null parent: null
// Button { padding: 64
// flat: true
// highlighted: true
// text: "Login"
// onClicked: stackView.push(loginPage) ListView {
// } anchors.fill: parent
id: accountSettingsListView
spacing: 0
delegate: RowLayout{
Label {
text: accountID
}
ItemDelegate {
text: "Logout"
onClicked: matriqueController.logout(connection);
}
}
}
} }
Page { Page {

View File

@ -11,7 +11,7 @@ import "component"
import "form" import "form"
ApplicationWindow { ApplicationWindow {
readonly property var connection: matriqueController.connection readonly property var currentConnection: accountListView.currentConnection ? accountListView.currentConnection : null
width: 960 width: 960
height: 640 height: 640
@ -42,6 +42,11 @@ ApplicationWindow {
} }
} }
AccountListModel {
id: accountListModel
controller: matriqueController
}
Popup { Popup {
property bool busy: matriqueController.busy property bool busy: matriqueController.busy
@ -71,13 +76,15 @@ ApplicationWindow {
parent: null parent: null
connection: accountListView.currentConnection connection: currentConnection
} }
Setting { Setting {
id: settingPage id: settingPage
parent: null parent: null
listModel: accountListModel
} }
RowLayout { RowLayout {
@ -104,7 +111,7 @@ ApplicationWindow {
id: accountListView id: accountListView
model: AccountListModel { controller: matriqueController } model: accountListModel
spacing: 0 spacing: 0
@ -176,7 +183,7 @@ ApplicationWindow {
} }
} }
onAccepted: matriqueController.createRoom(addRoomDialogNameTextField.text, addRoomDialogTopicTextField.text) onAccepted: matriqueController.createRoom(currentConnection, addRoomDialogNameTextField.text, addRoomDialogTopicTextField.text)
} }
} }
MenuItem { MenuItem {
@ -202,7 +209,7 @@ ApplicationWindow {
placeholderText: "#matrix:matrix.org" placeholderText: "#matrix:matrix.org"
} }
onAccepted: matriqueController.joinRoom(joinRoomDialogTextField.text) onAccepted: matriqueController.joinRoom(currentConnection, joinRoomDialogTextField.text)
} }
} }
@ -229,7 +236,7 @@ ApplicationWindow {
placeholderText: "@bot:matrix.org" placeholderText: "@bot:matrix.org"
} }
onAccepted: matriqueController.createDirectChat(directChatDialogTextField.text) onAccepted: currentConnection.createDirectChat(directChatDialogTextField.text)
} }
} }
} }
@ -283,13 +290,13 @@ ApplicationWindow {
id: stackView id: stackView
initialItem: roomPage // initialItem: roomPage
} }
} }
Binding { Binding {
target: imageProvider target: imageProvider
property: "connection" property: "connection"
value: accountListView.currentConnection value: currentConnection
} }
} }

View File

@ -27,6 +27,8 @@ void AccountListModel::setController(Controller* value) {
connect(m_controller, &Controller::connectionAdded, this, connect(m_controller, &Controller::connectionAdded, this,
[=](Connection* conn) { [=](Connection* conn) {
if (!conn) {
}
beginInsertRows(QModelIndex(), m_connections.count(), beginInsertRows(QModelIndex(), m_connections.count(),
m_connections.count()); m_connections.count());
m_connections.append(conn); m_connections.append(conn);
@ -34,6 +36,12 @@ void AccountListModel::setController(Controller* value) {
}); });
connect(m_controller, &Controller::connectionDropped, this, connect(m_controller, &Controller::connectionDropped, this,
[=](Connection* conn) { [=](Connection* conn) {
qDebug() << "Dropping connection" << conn->userId();
if (!conn) {
qDebug() << "Trying to remove null connection";
return;
}
conn->disconnect(this);
const auto it = const auto it =
std::find(m_connections.begin(), m_connections.end(), conn); std::find(m_connections.begin(), m_connections.end(), conn);
if (it == m_connections.end()) if (it == m_connections.end())
@ -50,15 +58,18 @@ void AccountListModel::setController(Controller* value) {
QVariant AccountListModel::data(const QModelIndex& index, int role) const { QVariant AccountListModel::data(const QModelIndex& index, int role) const {
if (!index.isValid()) return QVariant(); if (!index.isValid()) return QVariant();
if (index.row() >= m_controller->connections().count()) { if (index.row() >= m_connections.count()) {
qDebug() qDebug() << "AccountListModel, something's wrong: index.row() >= "
<< "UserListModel, something's wrong: index.row() >= m_users.count()"; "m_users.count()";
return QVariant(); return QVariant();
} }
auto m_connection = m_controller->connections().at(index.row()); auto m_connection = m_connections.at(index.row());
if (role == NameRole) { if (role == NameRole) {
return m_connection->user()->displayname(); return m_connection->user()->displayname();
} }
if (role == AccountIDRole) {
return m_connection->user()->id();
}
if (role == AvatarRole) { if (role == AvatarRole) {
return m_connection->user()->avatar(64); return m_connection->user()->avatar(64);
} }
@ -78,6 +89,7 @@ int AccountListModel::rowCount(const QModelIndex& parent) const {
QHash<int, QByteArray> AccountListModel::roleNames() const { QHash<int, QByteArray> AccountListModel::roleNames() const {
QHash<int, QByteArray> roles; QHash<int, QByteArray> roles;
roles[NameRole] = "name"; roles[NameRole] = "name";
roles[AccountIDRole] = "accountID";
roles[AvatarRole] = "avatar"; roles[AvatarRole] = "avatar";
roles[ConnectionRole] = "connection"; roles[ConnectionRole] = "connection";
return roles; return roles;

View File

@ -11,7 +11,12 @@ class AccountListModel : public QAbstractListModel {
Q_PROPERTY(Controller* controller READ controller WRITE setController NOTIFY Q_PROPERTY(Controller* controller READ controller WRITE setController NOTIFY
controllerChanged) controllerChanged)
public: public:
enum EventRoles { NameRole = Qt::UserRole + 1, AvatarRole, ConnectionRole }; enum EventRoles {
NameRole = Qt::UserRole + 1,
AccountIDRole,
AvatarRole,
ConnectionRole
};
AccountListModel(QObject* parent = nullptr); AccountListModel(QObject* parent = nullptr);

View File

@ -40,13 +40,17 @@ Controller::Controller(QObject* parent) : QObject(parent) {
Connection::setRoomType<MatriqueRoom>(); Connection::setRoomType<MatriqueRoom>();
invokeLogin(); QTimer::singleShot(0, this, SLOT(invokeLogin()));
} }
Controller::~Controller() { Controller::~Controller() {}
// m_connection->saveState();
// m_connection->stopSync(); inline QString accessTokenFileName(const AccountSettings& account) {
// m_connection->deleteLater(); QString fileName = account.userId();
fileName.replace(':', '_');
return QStandardPaths::writableLocation(
QStandardPaths::AppLocalDataLocation) +
'/' + fileName;
} }
void Controller::loginWithCredentials(QString serverAddr, QString user, void Controller::loginWithCredentials(QString serverAddr, QString user,
@ -70,18 +74,24 @@ void Controller::loginWithCredentials(QString serverAddr, QString user,
} }
} }
void Controller::logout(Connection* conn) {
if (!conn) {
qCritical() << "Attempt to logout null connection";
return;
}
SettingsGroup("Accounts").remove(conn->userId());
QFile(accessTokenFileName(AccountSettings(conn->userId()))).remove();
conn->logout();
}
void Controller::addConnection(Connection* c) { void Controller::addConnection(Connection* c) {
Q_ASSERT_X(c, __FUNCTION__, "Attempt to add a null connection"); Q_ASSERT_X(c, __FUNCTION__, "Attempt to add a null connection");
m_connections.push_back(c); m_connections.push_back(c);
connect(c, &Connection::syncDone, this, [=] { connect(c, &Connection::syncDone, this, [=] {
// gotEvents(c);
// Borrowed the logic from Quiark's code in Tensor to cache not too
// aggressively and not on the first sync. The static variable instance
// is created per-closure, meaning per-connection (which is why this
// code is not in gotEvents() ).
static int counter = 0; static int counter = 0;
if (++counter % 17 == 2) c->saveState(); if (++counter % 17 == 2) c->saveState();
}); });
@ -98,23 +108,13 @@ void Controller::dropConnection(Connection* c) {
Q_ASSERT_X(c, __FUNCTION__, "Attempt to drop a null connection"); Q_ASSERT_X(c, __FUNCTION__, "Attempt to drop a null connection");
m_connections.removeOne(c); m_connections.removeOne(c);
Q_ASSERT(!m_connections.contains(c) && !c->syncJob()); emit connectionDropped(c);
emit connectionAdded(c);
c->deleteLater(); c->deleteLater();
} }
inline QString accessTokenFileName(const AccountSettings& account) {
QString fileName = account.userId();
fileName.replace(':', '_');
return QStandardPaths::writableLocation(
QStandardPaths::AppLocalDataLocation) +
'/' + fileName;
}
void Controller::invokeLogin() { void Controller::invokeLogin() {
using namespace QMatrixClient; using namespace QMatrixClient;
const auto accounts = SettingsGroup("Accounts").childGroups(); const auto accounts = SettingsGroup("Accounts").childGroups();
bool autoLoggedIn = false;
for (const auto& accountId : accounts) { for (const auto& accountId : accounts) {
AccountSettings account{accountId}; AccountSettings account{accountId};
if (!account.homeserver().isEmpty()) { if (!account.homeserver().isEmpty()) {
@ -130,7 +130,6 @@ void Controller::invokeLogin() {
account.clearAccessToken(); // Clean the old place account.clearAccessToken(); // Clean the old place
} }
autoLoggedIn = true;
auto c = new Connection(account.homeserver(), this); auto c = new Connection(account.homeserver(), this);
auto deviceName = account.deviceName(); auto deviceName = account.deviceName();
connect(c, &Connection::connected, this, [=] { connect(c, &Connection::connected, this, [=] {
@ -185,42 +184,20 @@ bool Controller::saveAccessToken(const AccountSettings& account,
return false; return false;
} }
void Controller::connected() { void Controller::joinRoom(Connection* c, const QString& alias) {
// setHomeserver(m_connection->homeserver().toString()); JoinRoomJob* joinRoomJob = c->joinRoom(alias);
// setUserID(m_connection->userId()); setBusy(true);
// setToken(m_connection->accessToken()); joinRoomJob->connect(joinRoomJob, &JoinRoomJob::finished,
// m_connection->loadState(); [=] { setBusy(false); });
// resync();
// setIsLogin(true);
} }
void Controller::resync() { /*m_connection->sync(30000);*/ void Controller::createRoom(Connection* c, const QString& name,
} const QString& topic) {
CreateRoomJob* createRoomJob =
void Controller::reconnect() { c->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
// qDebug() << "Connection lost. Reconnecting..."; setBusy(true);
// m_connection->connectWithToken(m_userID, m_token, ""); createRoomJob->connect(createRoomJob, &CreateRoomJob::finished,
} [=] { setBusy(false); });
void Controller::joinRoom(const QString& alias) {
// JoinRoomJob* joinRoomJob = m_connection->joinRoom(alias);
// setBusy(true);
// joinRoomJob->connect(joinRoomJob, &JoinRoomJob::finished,
// [=] { setBusy(false); });
}
void Controller::createRoom(const QString& name, const QString& topic) {
// CreateRoomJob* createRoomJob =
// ((Connection*)m_connection)
// ->createRoom(Connection::PublishRoom, "", name, topic,
// QStringList());
// setBusy(true);
// createRoomJob->connect(createRoomJob, &CreateRoomJob::finished,
// [=] { setBusy(false); });
}
void Controller::createDirectChat(const QString& userID) {
// m_connection->requestDirectChat(userID);
} }
void Controller::copyToClipboard(const QString& text) { void Controller::copyToClipboard(const QString& text) {

View File

@ -49,9 +49,6 @@ class Controller : public QObject {
bool m_busy = false; bool m_busy = false;
void connected();
void resync();
void reconnect();
QByteArray loadAccessToken(const AccountSettings& account); QByteArray loadAccessToken(const AccountSettings& account);
bool saveAccessToken(const AccountSettings& account, bool saveAccessToken(const AccountSettings& account,
const QByteArray& accessToken); const QByteArray& accessToken);
@ -69,9 +66,9 @@ class Controller : public QObject {
void connectionDropped(Connection* conn); void connectionDropped(Connection* conn);
public slots: public slots:
void joinRoom(const QString& alias); void logout(Connection* conn);
void createRoom(const QString& name, const QString& topic); void joinRoom(Connection* c, const QString& alias);
void createDirectChat(const QString& userID); void createRoom(Connection* c, const QString& name, const QString& topic);
void copyToClipboard(const QString& text); void copyToClipboard(const QString& text);
void playAudio(QUrl localFile); void playAudio(QUrl localFile);
void showMessage(const QString& title, const QString& msg, const QIcon& icon); void showMessage(const QString& title, const QString& msg, const QIcon& icon);

View File

@ -51,7 +51,6 @@ void MessageEventModel::setRoom(MatriqueRoom* room) {
beginResetModel(); beginResetModel();
if (m_currentRoom) { if (m_currentRoom) {
m_currentRoom->disconnect(this); m_currentRoom->disconnect(this);
qDebug() << "Disconnected from" << m_currentRoom->id();
} }
m_currentRoom = room; m_currentRoom = room;

View File

@ -14,7 +14,16 @@ RoomListModel::RoomListModel(QObject* parent) : QAbstractListModel(parent) {}
RoomListModel::~RoomListModel() {} RoomListModel::~RoomListModel() {}
void RoomListModel::setConnection(Connection* connection) { void RoomListModel::setConnection(Connection* connection) {
if (!connection && connection == m_connection) return; if (connection == m_connection) return;
if (!connection) {
qDebug() << "Removing current connection...";
m_connection->disconnect(this);
m_connection = nullptr;
beginResetModel();
m_rooms.clear();
endResetModel();
return;
}
using QMatrixClient::Room; using QMatrixClient::Room;
m_connection = connection; m_connection = connection;