Clang-tidy + clang-format

This commit is contained in:
Carl Schwan
2020-11-27 00:19:54 +01:00
parent 49881f809d
commit 136a8f2af8
31 changed files with 470 additions and 332 deletions

View File

@@ -29,8 +29,9 @@ AccountListModel::AccountListModel(QObject *parent)
} }
conn->disconnect(this); conn->disconnect(this);
const auto it = std::find(m_connections.begin(), m_connections.end(), conn); const auto it = std::find(m_connections.begin(), m_connections.end(), conn);
if (it == m_connections.end()) if (it == m_connections.end()) {
return; // Already deleted, nothing to do return; // Already deleted, nothing to do
}
const int row = it - m_connections.begin(); const int row = it - m_connections.begin();
beginRemoveRows(QModelIndex(), row, row); beginRemoveRows(QModelIndex(), row, row);
m_connections.erase(it); m_connections.erase(it);

View File

@@ -22,10 +22,10 @@ public:
AccountListModel(QObject *parent = nullptr); AccountListModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = UserRole) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = UserRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
private: private:
QVector<Connection *> m_connections; QVector<Connection *> m_connections;

View File

@@ -3,9 +3,9 @@
#include <QQmlFile> #include <QQmlFile>
#include <QQmlFileSelector> #include <QQmlFileSelector>
#include <QQuickTextDocument> #include <QQuickTextDocument>
#include <QStringBuilder>
#include <QTextBlock> #include <QTextBlock>
#include <QTextDocument> #include <QTextDocument>
#include <QStringBuilder>
#include "neochatroom.h" #include "neochatroom.h"
@@ -23,11 +23,13 @@ QQuickTextDocument *ChatDocumentHandler::document() const
void ChatDocumentHandler::setDocument(QQuickTextDocument *document) void ChatDocumentHandler::setDocument(QQuickTextDocument *document)
{ {
if (document == m_document) if (document == m_document) {
return; return;
}
if (m_document) if (m_document) {
m_document->textDocument()->disconnect(this); m_document->textDocument()->disconnect(this);
}
m_document = document; m_document = document;
Q_EMIT documentChanged(); Q_EMIT documentChanged();
} }
@@ -39,14 +41,14 @@ int ChatDocumentHandler::cursorPosition() const
void ChatDocumentHandler::setCursorPosition(int position) void ChatDocumentHandler::setCursorPosition(int position)
{ {
if (position == m_cursorPosition) if (position == m_cursorPosition) {
return; return;
}
m_cursorPosition = position; m_cursorPosition = position;
Q_EMIT cursorPositionChanged(); Q_EMIT cursorPositionChanged();
} }
int ChatDocumentHandler::selectionStart() const int ChatDocumentHandler::selectionStart() const
{ {
return m_selectionStart; return m_selectionStart;
@@ -54,8 +56,9 @@ int ChatDocumentHandler::selectionStart() const
void ChatDocumentHandler::setSelectionStart(int position) void ChatDocumentHandler::setSelectionStart(int position)
{ {
if (position == m_selectionStart) if (position == m_selectionStart) {
return; return;
}
m_selectionStart = position; m_selectionStart = position;
Q_EMIT selectionStartChanged(); Q_EMIT selectionStartChanged();
@@ -68,8 +71,9 @@ int ChatDocumentHandler::selectionEnd() const
void ChatDocumentHandler::setSelectionEnd(int position) void ChatDocumentHandler::setSelectionEnd(int position)
{ {
if (position == m_selectionEnd) if (position == m_selectionEnd) {
return; return;
}
m_selectionEnd = position; m_selectionEnd = position;
Q_EMIT selectionEndChanged(); Q_EMIT selectionEndChanged();
@@ -78,8 +82,9 @@ void ChatDocumentHandler::setSelectionEnd(int position)
QTextCursor ChatDocumentHandler::textCursor() const QTextCursor ChatDocumentHandler::textCursor() const
{ {
QTextDocument *doc = textDocument(); QTextDocument *doc = textDocument();
if (!doc) if (!doc) {
return QTextCursor(); return QTextCursor();
}
QTextCursor cursor = QTextCursor(doc); QTextCursor cursor = QTextCursor(doc);
if (m_selectionStart != m_selectionEnd) { if (m_selectionStart != m_selectionEnd) {
@@ -93,8 +98,9 @@ QTextCursor ChatDocumentHandler::textCursor() const
QTextDocument *ChatDocumentHandler::textDocument() const QTextDocument *ChatDocumentHandler::textDocument() const
{ {
if (!m_document) if (!m_document) {
return nullptr; return nullptr;
}
return m_document->textDocument(); return m_document->textDocument();
} }
@@ -106,8 +112,9 @@ NeoChatRoom *ChatDocumentHandler::room() const
void ChatDocumentHandler::setRoom(NeoChatRoom *room) void ChatDocumentHandler::setRoom(NeoChatRoom *room)
{ {
if (m_room == room) if (m_room == room) {
return; return;
}
m_room = room; m_room = room;
Q_EMIT roomChanged(); Q_EMIT roomChanged();
@@ -123,8 +130,7 @@ QVariantMap ChatDocumentHandler::getAutocompletionInfo()
{"type", AutoCompletionType::Ignore}, {"type", AutoCompletionType::Ignore},
}; };
} }
if (m_cursorPosition != m_autoCompleteBeginPosition if (m_cursorPosition != m_autoCompleteBeginPosition && m_cursorPosition != m_autoCompleteEndPosition) {
&& m_cursorPosition != m_autoCompleteEndPosition) {
// we moved our cursor, so cancel autocompletion // we moved our cursor, so cancel autocompletion
} }
@@ -149,12 +155,11 @@ QVariantMap ChatDocumentHandler::getAutocompletionInfo()
{"keyword", autoCompletePrefix}, {"keyword", autoCompletePrefix},
{"type", AutoCompletionType::User}, {"type", AutoCompletionType::User},
}; };
} else {
return QVariantMap {
{"keyword", autoCompletePrefix},
{"type", AutoCompletionType::Emoji},
};
} }
return QVariantMap {
{"keyword", autoCompletePrefix},
{"type", AutoCompletionType::Emoji},
};
} }
return QVariantMap { return QVariantMap {
@@ -164,8 +169,9 @@ QVariantMap ChatDocumentHandler::getAutocompletionInfo()
void ChatDocumentHandler::postMessage(const QString &attachementPath, const QString &replyEventId) const void ChatDocumentHandler::postMessage(const QString &attachementPath, const QString &replyEventId) const
{ {
if (!m_room || !m_document) if (!m_room || !m_document) {
return; return;
}
QString cleanedText = m_document->textDocument()->toMarkdown(); QString cleanedText = m_document->textDocument()->toMarkdown();
@@ -175,8 +181,9 @@ void ChatDocumentHandler::postMessage(const QString &attachementPath, const QStr
m_room->uploadFile(attachementPath, cleanedText); m_room->uploadFile(attachementPath, cleanedText);
} }
if (cleanedText.length() == 0) if (cleanedText.length() == 0) {
return; return;
}
auto messageEventType = RoomMessageEvent::MsgType::Text; auto messageEventType = RoomMessageEvent::MsgType::Text;
@@ -187,7 +194,8 @@ void ChatDocumentHandler::postMessage(const QString &attachementPath, const QStr
if (cleanedText.indexOf(rainbowPrefix) == 0) { if (cleanedText.indexOf(rainbowPrefix) == 0) {
cleanedText = cleanedText.remove(0, rainbowPrefix.length()); cleanedText = cleanedText.remove(0, rainbowPrefix.length());
QString rainbowText; QString rainbowText;
QStringList rainbowColors { "#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", "#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff", "#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff", "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000" }; QStringList rainbowColors {"#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", "#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff",
"#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff", "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"};
for (int i = 0; i < cleanedText.length(); i++) { for (int i = 0; i < cleanedText.length(); i++) {
rainbowText = rainbowText % QStringLiteral("<font color='") % rainbowColors.at(i % rainbowColors.length()) % "'>" % cleanedText.at(i) % "</font>"; rainbowText = rainbowText % QStringLiteral("<font color='") % rainbowColors.at(i % rainbowColors.length()) % "'>" % cleanedText.at(i) % "</font>";

View File

@@ -34,24 +34,24 @@ public:
}; };
Q_ENUM(AutoCompletionType) Q_ENUM(AutoCompletionType)
explicit ChatDocumentHandler(QObject *object = nullptr); explicit ChatDocumentHandler(QObject *parent = nullptr);
QQuickTextDocument *document() const; [[nodiscard]] QQuickTextDocument *document() const;
void setDocument(QQuickTextDocument *document); void setDocument(QQuickTextDocument *document);
int cursorPosition() const; [[nodiscard]] int cursorPosition() const;
void setCursorPosition(int position); void setCursorPosition(int position);
int selectionStart() const; [[nodiscard]] int selectionStart() const;
void setSelectionStart(int position); void setSelectionStart(int position);
int selectionEnd() const; [[nodiscard]] int selectionEnd() const;
void setSelectionEnd(int position); void setSelectionEnd(int position);
NeoChatRoom *room() const; [[nodiscard]] NeoChatRoom *room() const;
void setRoom(NeoChatRoom *room); void setRoom(NeoChatRoom *room);
Q_INVOKABLE void postMessage(const QString &attachmentPath, const QString &replyEventId) const; Q_INVOKABLE void postMessage(const QString &attachementPath, const QString &replyEventId) const;
/// This function will look at the current QTextCursor and determine if there /// This function will look at the current QTextCursor and determine if there
/// is the posibility to autocomplete it. /// is the posibility to autocomplete it.
@@ -66,8 +66,8 @@ Q_SIGNALS:
void roomChanged(); void roomChanged();
private: private:
QTextCursor textCursor() const; [[nodiscard]] QTextCursor textCursor() const;
QTextDocument *textDocument() const; [[nodiscard]] QTextDocument *textDocument() const;
QQuickTextDocument *m_document; QQuickTextDocument *m_document;

View File

@@ -31,15 +31,17 @@ QImage Clipboard::image() const
return m_clipboard->image(); return m_clipboard->image();
} }
bool Clipboard::saveImage(const QUrl &localPath) bool Clipboard::saveImage(const QUrl &localPath) const
{ {
if (!localPath.isLocalFile()) if (!localPath.isLocalFile()) {
return false; return false;
}
auto i = image(); auto i = image();
if (i.isNull()) if (i.isNull()) {
return false; return false;
}
QString path = QFileInfo(localPath.toLocalFile()).absolutePath(); QString path = QFileInfo(localPath.toLocalFile()).absolutePath();
QDir dir; QDir dir;

View File

@@ -22,10 +22,10 @@ class Clipboard : public QObject
public: public:
explicit Clipboard(QObject *parent = nullptr); explicit Clipboard(QObject *parent = nullptr);
bool hasImage() const; [[nodiscard]] bool hasImage() const;
QImage image() const; [[nodiscard]] QImage image() const;
Q_INVOKABLE bool saveImage(const QUrl &localPath); Q_INVOKABLE bool saveImage(const QUrl &localPath) const;
Q_INVOKABLE void saveText(QString message); Q_INVOKABLE void saveText(QString message);

View File

@@ -31,14 +31,15 @@
#include <QtGui/QPixmap> #include <QtGui/QPixmap>
#include <QtNetwork/QAuthenticator> #include <QtNetwork/QAuthenticator>
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <utility>
#include "csapi/account-data.h" #include "csapi/account-data.h"
#include "csapi/content-repo.h" #include "csapi/content-repo.h"
#include "csapi/joining.h" #include "csapi/joining.h"
#include "csapi/logout.h" #include "csapi/logout.h"
#include "csapi/profile.h" #include "csapi/profile.h"
#include "csapi/wellknown.h"
#include "csapi/registration.h" #include "csapi/registration.h"
#include "csapi/wellknown.h"
#include "events/eventcontent.h" #include "events/eventcontent.h"
#include "events/roommessageevent.h" #include "events/roommessageevent.h"
#include "neochatroom.h" #include "neochatroom.h"
@@ -91,7 +92,7 @@ inline QString accessTokenFileName(const AccountSettings &account)
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/' + fileName; return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/' + fileName;
} }
void Controller::loginWithCredentials(QString serverAddr, QString user, QString pass, QString deviceName) void Controller::loginWithCredentials(const QString &serverAddr, const QString &user, const QString &pass, QString deviceName)
{ {
if (user.isEmpty() || pass.isEmpty()) { if (user.isEmpty() || pass.isEmpty()) {
return; return;
@@ -121,17 +122,18 @@ void Controller::loginWithCredentials(QString serverAddr, QString user, QString
account.setHomeserver(finalConn->homeserver()); account.setHomeserver(finalConn->homeserver());
account.setDeviceId(finalConn->deviceId()); account.setDeviceId(finalConn->deviceId());
account.setDeviceName(deviceName); account.setDeviceName(deviceName);
if (!saveAccessTokenToKeyChain(account, finalConn->accessToken())) if (!saveAccessTokenToKeyChain(account, finalConn->accessToken())) {
qWarning() << "Couldn't save access token"; qWarning() << "Couldn't save access token";
}
account.sync(); account.sync();
addConnection(finalConn); addConnection(finalConn);
setActiveConnection(finalConn); setActiveConnection(finalConn);
}); });
connect(finalConn, &Connection::networkError, [=](QString error, QString, int, int) { connect(finalConn, &Connection::networkError, [=](QString error, const QString &, int, int) {
Q_EMIT globalErrorOccured(i18n("Network Error"), error); Q_EMIT globalErrorOccured(i18n("Network Error"), std::move(error));
}); });
connect(finalConn, &Connection::loginError, [=](QString error, QString) { connect(finalConn, &Connection::loginError, [=](QString error, const QString &) {
Q_EMIT errorOccured(i18n("Login Failed"), error); Q_EMIT errorOccured(i18n("Login Failed"), std::move(error));
}); });
} }
}); });
@@ -142,7 +144,7 @@ void Controller::loginWithCredentials(QString serverAddr, QString user, QString
} }
} }
void Controller::loginWithAccessToken(QString serverAddr, QString user, QString token, QString deviceName) void Controller::loginWithAccessToken(const QString &serverAddr, const QString &user, const QString &token, const QString &deviceName)
{ {
if (user.isEmpty() || token.isEmpty()) { if (user.isEmpty() || token.isEmpty()) {
return; return;
@@ -162,14 +164,15 @@ void Controller::loginWithAccessToken(QString serverAddr, QString user, QString
account.setHomeserver(conn->homeserver()); account.setHomeserver(conn->homeserver());
account.setDeviceId(conn->deviceId()); account.setDeviceId(conn->deviceId());
account.setDeviceName(deviceName); account.setDeviceName(deviceName);
if (!saveAccessTokenToKeyChain(account, conn->accessToken())) if (!saveAccessTokenToKeyChain(account, conn->accessToken())) {
qWarning() << "Couldn't save access token"; qWarning() << "Couldn't save access token";
}
account.sync(); account.sync();
addConnection(conn); addConnection(conn);
setActiveConnection(conn); setActiveConnection(conn);
}); });
connect(conn, &Connection::networkError, this, [=](QString error, QString, int, int) { connect(conn, &Connection::networkError, this, [=](QString error, const QString &, int, int) {
Q_EMIT errorOccured("Network Error", error); Q_EMIT errorOccured("Network Error", std::move(error));
}); });
conn->connectWithToken(user, token, deviceName); conn->connectWithToken(user, token, deviceName);
} }
@@ -200,10 +203,11 @@ void Controller::logout(Connection *conn, bool serverSideLogout)
conn->stopSync(); conn->stopSync();
Q_EMIT conn->stateChanged(); Q_EMIT conn->stateChanged();
Q_EMIT conn->loggedOut(); Q_EMIT conn->loggedOut();
if (!m_connections.isEmpty()) if (!m_connections.isEmpty()) {
setActiveConnection(m_connections[0]); setActiveConnection(m_connections[0]);
else } else {
setActiveConnection(nullptr); setActiveConnection(nullptr);
}
if (!serverSideLogout) { if (!serverSideLogout) {
return; return;
} }
@@ -262,7 +266,7 @@ void Controller::invokeLogin()
c->loadState(); c->loadState();
addConnection(c); addConnection(c);
}); });
connect(c, &Connection::loginError, this, [=](QString error, QString) { connect(c, &Connection::loginError, this, [=](const QString &error, const QString &) {
if (error == "Unrecognised access token") { if (error == "Unrecognised access token") {
Q_EMIT errorOccured(i18n("Login Failed"), i18n("Access Token invalid or revoked")); Q_EMIT errorOccured(i18n("Login Failed"), i18n("Access Token invalid or revoked"));
logout(c, false); logout(c, false);
@@ -271,7 +275,7 @@ void Controller::invokeLogin()
logout(c, true); logout(c, true);
} }
}); });
connect(c, &Connection::networkError, this, [=](QString error, QString, int, int) { connect(c, &Connection::networkError, this, [=](const QString &error, const QString &, int, int) {
Q_EMIT errorOccured("Network Error", error); Q_EMIT errorOccured("Network Error", error);
}); });
c->connectWithToken(account.userId(), accessToken, account.deviceId()); c->connectWithToken(account.userId(), accessToken, account.deviceId());
@@ -289,8 +293,9 @@ QByteArray Controller::loadAccessTokenFromFile(const AccountSettings &account)
{ {
QFile accountTokenFile {accessTokenFileName(account)}; QFile accountTokenFile {accessTokenFileName(account)};
if (accountTokenFile.open(QFile::ReadOnly)) { if (accountTokenFile.open(QFile::ReadOnly)) {
if (accountTokenFile.size() < 1024) if (accountTokenFile.size() < 1024) {
return accountTokenFile.readAll(); return accountTokenFile.readAll();
}
qWarning() << "File" << accountTokenFile.fileName() << "is" << accountTokenFile.size() << "bytes long - too long for a token, ignoring it."; qWarning() << "File" << accountTokenFile.fileName() << "is" << accountTokenFile.size() << "bytes long - too long for a token, ignoring it.";
} }
@@ -388,12 +393,13 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const
void Controller::joinRoom(Connection *c, const QString &alias) void Controller::joinRoom(Connection *c, const QString &alias)
{ {
if (!alias.contains(":")) if (!alias.contains(":")) {
return; return;
}
auto knownServer = alias.mid(alias.indexOf(":") + 1); auto knownServer = alias.mid(alias.indexOf(":") + 1);
auto joinRoomJob = c->joinRoom(alias, QStringList {knownServer}); auto joinRoomJob = c->joinRoom(alias, QStringList {knownServer});
joinRoomJob->connect(joinRoomJob, &JoinRoomJob::failure, [=] { Quotient::JoinRoomJob::connect(joinRoomJob, &JoinRoomJob::failure, [=] {
Q_EMIT errorOccured("Join Room Failed", joinRoomJob->errorString()); Q_EMIT errorOccured("Join Room Failed", joinRoomJob->errorString());
}); });
} }
@@ -401,7 +407,7 @@ void Controller::joinRoom(Connection *c, const QString &alias)
void Controller::createRoom(Connection *c, const QString &name, const QString &topic) void Controller::createRoom(Connection *c, const QString &name, const QString &topic)
{ {
auto createRoomJob = c->createRoom(Connection::PublishRoom, "", name, topic, QStringList()); auto createRoomJob = c->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
createRoomJob->connect(createRoomJob, &CreateRoomJob::failure, [=] { Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::failure, [=] {
Q_EMIT errorOccured("Create Room Failed", createRoomJob->errorString()); Q_EMIT errorOccured("Create Room Failed", createRoomJob->errorString());
}); });
} }
@@ -409,12 +415,12 @@ void Controller::createRoom(Connection *c, const QString &name, const QString &t
void Controller::createDirectChat(Connection *c, const QString &userID) void Controller::createDirectChat(Connection *c, const QString &userID)
{ {
auto createRoomJob = c->createDirectChat(userID); auto createRoomJob = c->createDirectChat(userID);
createRoomJob->connect(createRoomJob, &CreateRoomJob::failure, [=] { Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::failure, [=] {
Q_EMIT errorOccured("Create Direct Chat Failed", createRoomJob->errorString()); Q_EMIT errorOccured("Create Direct Chat Failed", createRoomJob->errorString());
}); });
} }
void Controller::playAudio(QUrl localFile) void Controller::playAudio(const QUrl &localFile)
{ {
auto player = new QMediaPlayer; auto player = new QMediaPlayer;
player->setMedia(localFile); player->setMedia(localFile);
@@ -424,7 +430,7 @@ void Controller::playAudio(QUrl localFile)
}); });
} }
void Controller::changeAvatar(Connection *conn, QUrl localFile) void Controller::changeAvatar(Connection *conn, const QUrl &localFile)
{ {
auto job = conn->uploadFile(localFile.toLocalFile()); auto job = conn->uploadFile(localFile.toLocalFile());
if (isJobRunning(job)) { if (isJobRunning(job)) {
@@ -442,7 +448,7 @@ void Controller::markAllMessagesAsRead(Connection *conn)
} }
} }
void Controller::setAboutData(KAboutData aboutData) void Controller::setAboutData(const KAboutData &aboutData)
{ {
m_aboutData = aboutData; m_aboutData = aboutData;
Q_EMIT aboutDataChanged(); Q_EMIT aboutDataChanged();
@@ -488,7 +494,7 @@ NeochatChangePasswordJob::NeochatChangePasswordJob(const QString &newPassword, b
addParam<>(_data, QStringLiteral("new_password"), newPassword); addParam<>(_data, QStringLiteral("new_password"), newPassword);
addParam<IfNotEmpty>(_data, QStringLiteral("logout_devices"), logoutDevices); addParam<IfNotEmpty>(_data, QStringLiteral("logout_devices"), logoutDevices);
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth); addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
setRequestData(std::move(_data)); setRequestData(_data);
} }
QVector<Connection *> Controller::connections() const QVector<Connection *> Controller::connections() const
@@ -501,7 +507,7 @@ int Controller::accountCount() const
return m_connections.count(); return m_connections.count();
} }
bool Controller::quitOnLastWindowClosed() const bool Controller::quitOnLastWindowClosed()
{ {
return QApplication::quitOnLastWindowClosed(); return QApplication::quitOnLastWindowClosed();
} }
@@ -530,15 +536,17 @@ void Controller::setBusy(bool busy)
Connection *Controller::activeConnection() const Connection *Controller::activeConnection() const
{ {
if (m_connection.isNull()) if (m_connection.isNull()) {
return nullptr; return nullptr;
}
return m_connection; return m_connection;
} }
void Controller::setActiveConnection(Connection *connection) void Controller::setActiveConnection(Connection *connection)
{ {
if (connection == m_connection) if (connection == m_connection) {
return; return;
}
m_connection = connection; m_connection = connection;
Q_EMIT activeConnectionChanged(); Q_EMIT activeConnectionChanged();
} }

View File

@@ -33,29 +33,29 @@ class Controller : public QObject
public: public:
static Controller &instance(); static Controller &instance();
QVector<Connection *> connections() const; [[nodiscard]] QVector<Connection *> connections() const;
void setActiveConnection(Connection *connection); void setActiveConnection(Connection *connection);
Connection *activeConnection() const; [[nodiscard]] Connection *activeConnection() const;
void addConnection(Connection *c); void addConnection(Connection *c);
void dropConnection(Connection *c); void dropConnection(Connection *c);
Q_INVOKABLE void loginWithCredentials(QString, QString, QString, QString); Q_INVOKABLE void loginWithCredentials(const QString &, const QString &, const QString &, QString);
Q_INVOKABLE void loginWithAccessToken(QString, QString, QString, QString); Q_INVOKABLE void loginWithAccessToken(const QString &, const QString &, const QString &, const QString &);
Q_INVOKABLE void changePassword(Quotient::Connection *connection, const QString &currentPassword, const QString &newPassword); Q_INVOKABLE void changePassword(Quotient::Connection *connection, const QString &currentPassword, const QString &newPassword);
int accountCount() const; [[nodiscard]] int accountCount() const;
bool quitOnLastWindowClosed() const; [[nodiscard]] static bool quitOnLastWindowClosed();
void setQuitOnLastWindowClosed(bool value); void setQuitOnLastWindowClosed(bool value);
bool busy() const; [[nodiscard]] bool busy() const;
void setBusy(bool busy); void setBusy(bool busy);
void setAboutData(KAboutData aboutData); void setAboutData(const KAboutData &aboutData);
KAboutData aboutData() const; [[nodiscard]] KAboutData aboutData() const;
enum PasswordStatus { enum PasswordStatus {
Success, Success,
@@ -66,13 +66,13 @@ public:
private: private:
explicit Controller(QObject *parent = nullptr); explicit Controller(QObject *parent = nullptr);
~Controller(); ~Controller() override;
QVector<Connection *> m_connections; QVector<Connection *> m_connections;
QPointer<Connection> m_connection; QPointer<Connection> m_connection;
bool m_busy = false; bool m_busy = false;
QByteArray loadAccessTokenFromFile(const AccountSettings &account); static QByteArray loadAccessTokenFromFile(const AccountSettings &account);
QByteArray loadAccessTokenFromKeyChain(const AccountSettings &account); QByteArray loadAccessTokenFromKeyChain(const AccountSettings &account);
bool saveAccessTokenToFile(const AccountSettings &account, const QByteArray &accessToken); bool saveAccessTokenToFile(const AccountSettings &account, const QByteArray &accessToken);
@@ -88,20 +88,20 @@ private Q_SLOTS:
Q_SIGNALS: Q_SIGNALS:
void busyChanged(); void busyChanged();
/// Error occured because of user inputs /// Error occured because of user inputs
void errorOccured(QString error, QString detail); void errorOccured(QString _t1, QString _t2);
/// Error occured because of server or bug in NeoChat /// Error occured because of server or bug in NeoChat
void globalErrorOccured(QString error, QString detail); void globalErrorOccured(QString _t1, QString _t2);
void syncDone(); void syncDone();
void connectionAdded(Quotient::Connection *conn); void connectionAdded(Quotient::Connection *_t1);
void connectionDropped(Quotient::Connection *conn); void connectionDropped(Quotient::Connection *_t1);
void initiated(); void initiated();
void notificationClicked(const QString roomId, const QString eventId); void notificationClicked(const QString &_t1, const QString &_t2);
void quitOnLastWindowClosedChanged(); void quitOnLastWindowClosedChanged();
void unreadCountChanged(); void unreadCountChanged();
void activeConnectionChanged(); void activeConnectionChanged();
void aboutDataChanged(); void aboutDataChanged();
void passwordStatus(Controller::PasswordStatus status); void passwordStatus(Controller::PasswordStatus _t1);
void showWindow(); void showWindow();
public Q_SLOTS: public Q_SLOTS:
@@ -109,9 +109,9 @@ public Q_SLOTS:
void joinRoom(Quotient::Connection *c, const QString &alias); void joinRoom(Quotient::Connection *c, const QString &alias);
void createRoom(Quotient::Connection *c, const QString &name, const QString &topic); void createRoom(Quotient::Connection *c, const QString &name, const QString &topic);
void createDirectChat(Quotient::Connection *c, const QString &userID); void createDirectChat(Quotient::Connection *c, const QString &userID);
void playAudio(QUrl localFile); static void playAudio(const QUrl &localFile);
void changeAvatar(Quotient::Connection *conn, QUrl localFile); void changeAvatar(Quotient::Connection *conn, const QUrl &localFile);
void markAllMessagesAsRead(Quotient::Connection *conn); static void markAllMessagesAsRead(Quotient::Connection *conn);
}; };
// TODO libQuotient 0.7: Drop // TODO libQuotient 0.7: Drop

View File

@@ -70,7 +70,7 @@ QVariantList EmojiModel::filterModel(const QString &filter)
return result; return result;
} }
void EmojiModel::emojiUsed(QVariant modelData) void EmojiModel::emojiUsed(const QVariant &modelData)
{ {
QVariantList list = history(); QVariantList list = history();
@@ -78,8 +78,9 @@ void EmojiModel::emojiUsed(QVariant modelData)
while (it != list.end()) { while (it != list.end()) {
if ((*it).value<Emoji>().unicode == modelData.value<Emoji>().unicode) { if ((*it).value<Emoji>().unicode == modelData.value<Emoji>().unicode) {
it = list.erase(it); it = list.erase(it);
} else } else {
it++; it++;
}
} }
list.push_front(modelData); list.push_front(modelData);

View File

@@ -10,16 +10,15 @@
#include <QSettings> #include <QSettings>
#include <QVariant> #include <QVariant>
#include <QVector> #include <QVector>
#include <utility>
struct Emoji { struct Emoji {
Emoji(const QString &u, const QString &s) Emoji(QString u, QString s)
: unicode(u) : unicode(std::move(std::move(u)))
, shortname(s) , shortname(std::move(std::move(s)))
{
}
Emoji()
{ {
} }
Emoji() = default;
friend QDataStream &operator<<(QDataStream &arch, const Emoji &object) friend QDataStream &operator<<(QDataStream &arch, const Emoji &object)
{ {
@@ -67,13 +66,13 @@ public:
} }
Q_INVOKABLE QVariantList history(); Q_INVOKABLE QVariantList history();
Q_INVOKABLE QVariantList filterModel(const QString &filter); Q_INVOKABLE static QVariantList filterModel(const QString &filter);
Q_SIGNALS: Q_SIGNALS:
void historyChanged(); void historyChanged();
public Q_SLOTS: public Q_SLOTS:
void emojiUsed(QVariant modelData); void emojiUsed(const QVariant &modelData);
private: private:
static const QVariantList people; static const QVariantList people;

View File

@@ -23,6 +23,7 @@
#include "neochat-version.h" #include "neochat-version.h"
#include "accountlistmodel.h" #include "accountlistmodel.h"
#include "chatdocumenthandler.h"
#include "clipboard.h" #include "clipboard.h"
#include "controller.h" #include "controller.h"
#include "csapi/joining.h" #include "csapi/joining.h"
@@ -30,6 +31,7 @@
#include "emojimodel.h" #include "emojimodel.h"
#include "matriximageprovider.h" #include "matriximageprovider.h"
#include "messageeventmodel.h" #include "messageeventmodel.h"
#include "neochatconfig.h"
#include "neochatroom.h" #include "neochatroom.h"
#include "neochatuser.h" #include "neochatuser.h"
#include "notificationsmanager.h" #include "notificationsmanager.h"
@@ -39,8 +41,6 @@
#include "sortfilterroomlistmodel.h" #include "sortfilterroomlistmodel.h"
#include "userdirectorylistmodel.h" #include "userdirectorylistmodel.h"
#include "userlistmodel.h" #include "userlistmodel.h"
#include "neochatconfig.h"
#include "chatdocumenthandler.h"
using namespace Quotient; using namespace Quotient;
@@ -60,8 +60,8 @@ int main(int argc, char *argv[])
QApplication app(argc, argv); QApplication app(argc, argv);
#endif #endif
app.setOrganizationName("KDE"); QApplication::setOrganizationName("KDE");
app.setWindowIcon(QIcon(":/assets/img/icon.png")); QApplication::setWindowIcon(QIcon(":/assets/img/icon.png"));
KAboutData about(QStringLiteral("neochat"), i18n("Neochat"), QStringLiteral(NEOCHAT_VERSION_STRING), i18n("Matrix client"), KAboutLicense::GPL_V3, i18n("© 2018-2020 Black Hat, 2020 KDE Community")); KAboutData about(QStringLiteral("neochat"), i18n("Neochat"), QStringLiteral(NEOCHAT_VERSION_STRING), i18n("Matrix client"), KAboutLicense::GPL_V3, i18n("© 2018-2020 Black Hat, 2020 KDE Community"));
about.addAuthor(i18n("Black Hat"), QString(), QStringLiteral("bhat@encom.eu.org")); about.addAuthor(i18n("Black Hat"), QString(), QStringLiteral("bhat@encom.eu.org"));
@@ -123,14 +123,15 @@ int main(int argc, char *argv[])
engine.addImageProvider(QLatin1String("mxc"), new MatrixImageProvider); engine.addImageProvider(QLatin1String("mxc"), new MatrixImageProvider);
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
if (engine.rootObjects().isEmpty()) if (engine.rootObjects().isEmpty()) {
return -1; return -1;
}
#ifndef Q_OS_ANDROID #ifndef Q_OS_ANDROID
QObject::connect(&service, &KDBusService::activateRequested, &engine, [&engine](const QStringList &/*arguments*/, const QString &/*workingDirectory*/) { QObject::connect(&service, &KDBusService::activateRequested, &engine, [&engine](const QStringList & /*arguments*/, const QString & /*workingDirectory*/) {
const auto rootObjects = engine.rootObjects(); const auto rootObjects = engine.rootObjects();
for (auto obj : rootObjects) { for (auto obj : rootObjects) {
auto view = qobject_cast<QQuickWindow*>(obj); auto view = qobject_cast<QQuickWindow *>(obj);
if (view) { if (view) {
view->raise(); view->raise();
return; return;
@@ -138,5 +139,5 @@ int main(int argc, char *argv[])
} }
}); });
#endif #endif
return app.exec(); return QApplication::exec();
} }

View File

@@ -73,8 +73,9 @@ void ThumbnailResponse::prepareResult()
QString localPath = QFileInfo(localFile).absolutePath(); QString localPath = QFileInfo(localFile).absolutePath();
QDir dir; QDir dir;
if (!dir.exists(localPath)) if (!dir.exists(localPath)) {
dir.mkpath(localPath); dir.mkpath(localPath);
}
image.save(localFile); image.save(localFile);

View File

@@ -5,6 +5,7 @@
*/ */
#include "messageeventmodel.h" #include "messageeventmodel.h"
#include "neochatconfig.h"
#include <connection.h> #include <connection.h>
#include <events/reactionevent.h> #include <events/reactionevent.h>
#include <events/redactionevent.h> #include <events/redactionevent.h>
@@ -12,11 +13,10 @@
#include <events/roommemberevent.h> #include <events/roommemberevent.h>
#include <events/simplestateevents.h> #include <events/simplestateevents.h>
#include <user.h> #include <user.h>
#include "neochatconfig.h"
#include <QDebug> #include <QDebug>
#include <QTimeZone>
#include <QQmlEngine> // for qmlRegisterType() #include <QQmlEngine> // for qmlRegisterType()
#include <QTimeZone>
#include <KLocalizedString> #include <KLocalizedString>
@@ -70,14 +70,13 @@ MessageEventModel::MessageEventModel(QObject *parent)
}); });
} }
MessageEventModel::~MessageEventModel() MessageEventModel::~MessageEventModel() = default;
{
}
void MessageEventModel::setRoom(NeoChatRoom *room) void MessageEventModel::setRoom(NeoChatRoom *room)
{ {
if (room == m_currentRoom) if (room == m_currentRoom) {
return; return;
}
beginResetModel(); beginResetModel();
if (m_currentRoom) { if (m_currentRoom) {
@@ -93,8 +92,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
beginInsertRows({}, timelineBaseIndex(), timelineBaseIndex() + int(events.size()) - 1); beginInsertRows({}, timelineBaseIndex(), timelineBaseIndex() + int(events.size()) - 1);
}); });
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [=](RoomEventsRange events) { connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [=](RoomEventsRange events) {
if (rowCount() > 0) if (rowCount() > 0) {
rowBelowInserted = rowCount() - 1; // See #312 rowBelowInserted = rowCount() - 1; // See #312
}
beginInsertRows({}, rowCount(), rowCount() + int(events.size()) - 1); beginInsertRows({}, rowCount(), rowCount() + int(events.size()) - 1);
}); });
connect(m_currentRoom, &Room::addedMessages, this, [=](int lowest, int biggest) { connect(m_currentRoom, &Room::addedMessages, this, [=](int lowest, int biggest) {
@@ -103,16 +103,18 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
auto rowBelowInserted = m_currentRoom->maxTimelineIndex() - biggest + timelineBaseIndex() - 1; auto rowBelowInserted = m_currentRoom->maxTimelineIndex() - biggest + timelineBaseIndex() - 1;
refreshEventRoles(rowBelowInserted, {ShowAuthorRole}); refreshEventRoles(rowBelowInserted, {ShowAuthorRole});
} }
for (auto i = m_currentRoom->maxTimelineIndex() - biggest; i <= m_currentRoom->maxTimelineIndex() - lowest; ++i) for (auto i = m_currentRoom->maxTimelineIndex() - biggest; i <= m_currentRoom->maxTimelineIndex() - lowest; ++i) {
refreshLastUserEvents(i); refreshLastUserEvents(i);
}
}); });
connect(m_currentRoom, &Room::pendingEventAboutToAdd, this, [this] { connect(m_currentRoom, &Room::pendingEventAboutToAdd, this, [this] {
beginInsertRows({}, 0, 0); beginInsertRows({}, 0, 0);
}); });
connect(m_currentRoom, &Room::pendingEventAdded, this, &MessageEventModel::endInsertRows); connect(m_currentRoom, &Room::pendingEventAdded, this, &MessageEventModel::endInsertRows);
connect(m_currentRoom, &Room::pendingEventAboutToMerge, this, [this](RoomEvent *, int i) { connect(m_currentRoom, &Room::pendingEventAboutToMerge, this, [this](RoomEvent *, int i) {
if (i == 0) if (i == 0) {
return; // No need to move anything, just refresh return; // No need to move anything, just refresh
}
movingEvent = true; movingEvent = true;
// Reverse i because row 0 is bottommost in the model // Reverse i because row 0 is bottommost in the model
@@ -126,10 +128,12 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
} }
refreshRow(timelineBaseIndex()); // Refresh the looks refreshRow(timelineBaseIndex()); // Refresh the looks
refreshLastUserEvents(0); refreshLastUserEvents(0);
if (m_currentRoom->timelineSize() > 1) // Refresh above if (m_currentRoom->timelineSize() > 1) { // Refresh above
refreshEventRoles(timelineBaseIndex() + 1, {ReadMarkerRole}); refreshEventRoles(timelineBaseIndex() + 1, {ReadMarkerRole});
if (timelineBaseIndex() > 0) // Refresh below, see #312 }
if (timelineBaseIndex() > 0) { // Refresh below, see #312
refreshEventRoles(timelineBaseIndex() - 1, {ShowAuthorRole}); refreshEventRoles(timelineBaseIndex() - 1, {ShowAuthorRole});
}
}); });
connect(m_currentRoom, &Room::pendingEventChanged, this, &MessageEventModel::refreshRow); connect(m_currentRoom, &Room::pendingEventChanged, this, &MessageEventModel::refreshRow);
connect(m_currentRoom, &Room::pendingEventAboutToDiscard, this, [this](int i) { connect(m_currentRoom, &Room::pendingEventAboutToDiscard, this, [this](int i) {
@@ -153,7 +157,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
connect(m_currentRoom, &Room::fileTransferCompleted, this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferCompleted, this, &MessageEventModel::refreshEvent);
connect(m_currentRoom, &Room::fileTransferFailed, this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferFailed, this, &MessageEventModel::refreshEvent);
connect(m_currentRoom, &Room::fileTransferCancelled, this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferCancelled, this, &MessageEventModel::refreshEvent);
connect(m_currentRoom, &Room::readMarkerForUserMoved, this, [=](User *, QString fromEventId, QString toEventId) { connect(m_currentRoom, &Room::readMarkerForUserMoved, this, [=](User *, const QString &fromEventId, const QString &toEventId) {
refreshEventRoles(fromEventId, {UserMarkerRole}); refreshEventRoles(fromEventId, {UserMarkerRole});
refreshEventRoles(toEventId, {UserMarkerRole}); refreshEventRoles(toEventId, {UserMarkerRole});
}); });
@@ -162,8 +166,9 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
endResetModel(); endResetModel();
}); });
qDebug() << "Connected to room" << room->id() << "as" << room->localUser()->id(); qDebug() << "Connected to room" << room->id() << "as" << room->localUser()->id();
} else } else {
lastReadEventId.clear(); lastReadEventId.clear();
}
endResetModel(); endResetModel();
} }
@@ -195,9 +200,9 @@ int MessageEventModel::refreshEventRoles(const QString &id, const QVector<int> &
int row = -1; int row = -1;
// First try pendingEvents because it is almost always very short. // First try pendingEvents because it is almost always very short.
const auto pendingIt = m_currentRoom->findPendingEvent(id); const auto pendingIt = m_currentRoom->findPendingEvent(id);
if (pendingIt != m_currentRoom->pendingEvents().end()) if (pendingIt != m_currentRoom->pendingEvents().end()) {
row = int(pendingIt - m_currentRoom->pendingEvents().begin()); row = int(pendingIt - m_currentRoom->pendingEvents().begin());
else { } else {
const auto timelineIt = m_currentRoom->findInTimeline(id); const auto timelineIt = m_currentRoom->findInTimeline(id);
if (timelineIt == m_currentRoom->timelineEdge()) { if (timelineIt == m_currentRoom->timelineEdge()) {
qWarning() << "Trying to refresh inexistent event:" << id; qWarning() << "Trying to refresh inexistent event:" << id;
@@ -218,43 +223,51 @@ QDateTime MessageEventModel::makeMessageTimestamp(const Quotient::Room::rev_iter
{ {
const auto &timeline = m_currentRoom->messageEvents(); const auto &timeline = m_currentRoom->messageEvents();
auto ts = baseIt->event()->originTimestamp(); auto ts = baseIt->event()->originTimestamp();
if (ts.isValid()) if (ts.isValid()) {
return ts; return ts;
}
// The event is most likely redacted or just invalid. // The event is most likely redacted or just invalid.
// Look for the nearest date around and slap zero time to it. // Look for the nearest date around and slap zero time to it.
using Quotient::TimelineItem; using Quotient::TimelineItem;
auto rit = std::find_if(baseIt, timeline.rend(), hasValidTimestamp); auto rit = std::find_if(baseIt, timeline.rend(), hasValidTimestamp);
if (rit != timeline.rend()) if (rit != timeline.rend()) {
return {rit->event()->originTimestamp().date(), {0, 0}, Qt::LocalTime}; return {rit->event()->originTimestamp().date(), {0, 0}, Qt::LocalTime};
};
auto it = std::find_if(baseIt.base(), timeline.end(), hasValidTimestamp); auto it = std::find_if(baseIt.base(), timeline.end(), hasValidTimestamp);
if (it != timeline.end()) if (it != timeline.end()) {
return {it->event()->originTimestamp().date(), {0, 0}, Qt::LocalTime}; return {it->event()->originTimestamp().date(), {0, 0}, Qt::LocalTime};
};
// What kind of room is that?.. // What kind of room is that?..
qCritical() << "No valid timestamps in the room timeline!"; qCritical() << "No valid timestamps in the room timeline!";
return {}; return {};
} }
QString MessageEventModel::renderDate(QDateTime timestamp) const QString MessageEventModel::renderDate(const QDateTime &timestamp)
{ {
auto date = timestamp.toLocalTime().date(); auto date = timestamp.toLocalTime().date();
if (date == QDate::currentDate()) if (date == QDate::currentDate()) {
return i18n("Today"); return i18n("Today");
if (date == QDate::currentDate().addDays(-1)) }
if (date == QDate::currentDate().addDays(-1)) {
return i18n("Yesterday"); return i18n("Yesterday");
if (date == QDate::currentDate().addDays(-2)) }
if (date == QDate::currentDate().addDays(-2)) {
return i18n("The day before yesterday"); return i18n("The day before yesterday");
if (date > QDate::currentDate().addDays(-7)) }
if (date > QDate::currentDate().addDays(-7)) {
return date.toString("dddd"); return date.toString("dddd");
}
return QLocale::system().toString(date, QLocale::ShortFormat); return QLocale::system().toString(date, QLocale::ShortFormat);
} }
void MessageEventModel::refreshLastUserEvents(int baseTimelineRow) void MessageEventModel::refreshLastUserEvents(int baseTimelineRow)
{ {
if (!m_currentRoom || m_currentRoom->timelineSize() <= baseTimelineRow) if (!m_currentRoom || m_currentRoom->timelineSize() <= baseTimelineRow) {
return; return;
}
const auto &timelineBottom = m_currentRoom->messageEvents().rbegin(); const auto &timelineBottom = m_currentRoom->messageEvents().rbegin();
const auto &lastSender = (*(timelineBottom + baseTimelineRow))->senderId(); const auto &lastSender = (*(timelineBottom + baseTimelineRow))->senderId();
@@ -269,8 +282,9 @@ void MessageEventModel::refreshLastUserEvents(int baseTimelineRow)
int MessageEventModel::rowCount(const QModelIndex &parent) const int MessageEventModel::rowCount(const QModelIndex &parent) const
{ {
if (!m_currentRoom || parent.isValid()) if (!m_currentRoom || parent.isValid()) {
return 0; return 0;
}
return m_currentRoom->timelineSize(); return m_currentRoom->timelineSize();
} }
@@ -292,8 +306,9 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
{ {
const auto row = idx.row(); const auto row = idx.row();
if (!m_currentRoom || row < 0 || row >= int(m_currentRoom->pendingEvents().size()) + m_currentRoom->timelineSize()) if (!m_currentRoom || row < 0 || row >= int(m_currentRoom->pendingEvents().size()) + m_currentRoom->timelineSize()) {
return {}; return {};
};
bool isPending = row < timelineBaseIndex(); bool isPending = row < timelineBaseIndex();
const auto timelineIt = m_currentRoom->messageEvents().crbegin() + std::max(0, row - timelineBaseIndex()); const auto timelineIt = m_currentRoom->messageEvents().crbegin() + std::max(0, row - timelineBaseIndex());
@@ -338,14 +353,16 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
return "message"; return "message";
} }
if (evt.isStateEvent()) if (evt.isStateEvent()) {
return "state"; return "state";
}
return "other"; return "other";
} }
if (role == EventResolvedTypeRole) if (role == EventResolvedTypeRole) {
return EventTypeRegistry::getMatrixType(evt.type()); return EventTypeRegistry::getMatrixType(evt.type());
}
if (role == AuthorRole) { if (role == AuthorRole) {
auto author = static_cast<NeoChatUser *>(isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId())); auto author = static_cast<NeoChatUser *>(isPending ? m_currentRoom->localUser() : m_currentRoom->user(evt.senderId()));
@@ -374,29 +391,36 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}; };
} }
if (role == HighlightRole) if (role == HighlightRole) {
return m_currentRoom->isEventHighlighted(&evt); return m_currentRoom->isEventHighlighted(&evt);
}
if (role == ReadMarkerRole) if (role == ReadMarkerRole) {
return evt.id() == lastReadEventId && row > timelineBaseIndex(); return evt.id() == lastReadEventId && row > timelineBaseIndex();
}
if (role == SpecialMarksRole) { if (role == SpecialMarksRole) {
if (isPending) if (isPending) {
return pendingIt->deliveryStatus(); return pendingIt->deliveryStatus();
}
auto *memberEvent = timelineIt->viewAs<RoomMemberEvent>(); auto *memberEvent = timelineIt->viewAs<RoomMemberEvent>();
if (memberEvent) { if (memberEvent) {
if ((memberEvent->isJoin() || memberEvent->isLeave()) && !NeoChatConfig::self()->showLeaveJoinEvent()) if ((memberEvent->isJoin() || memberEvent->isLeave()) && !NeoChatConfig::self()->showLeaveJoinEvent()) {
return EventStatus::Hidden; return EventStatus::Hidden;
}
} }
if (is<RedactionEvent>(evt) || is<ReactionEvent>(evt)) if (is<RedactionEvent>(evt) || is<ReactionEvent>(evt)) {
return EventStatus::Hidden; return EventStatus::Hidden;
if (evt.isRedacted()) }
if (evt.isRedacted()) {
return EventStatus::Hidden; return EventStatus::Hidden;
}
if (evt.isStateEvent() && static_cast<const StateEventBase &>(evt).repeatsState()) if (evt.isStateEvent() && static_cast<const StateEventBase &>(evt).repeatsState()) {
return EventStatus::Hidden; return EventStatus::Hidden;
}
if (auto e = eventCast<const RoomMessageEvent>(&evt)) { if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
if (!e->replacedEvent().isEmpty() && e->replacedEvent() != e->id()) { if (!e->replacedEvent().isEmpty() && e->replacedEvent() != e->id()) {
@@ -404,24 +428,30 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
} }
} }
if (m_currentRoom->connection()->isIgnored(m_currentRoom->user(evt.senderId()))) if (m_currentRoom->connection()->isIgnored(m_currentRoom->user(evt.senderId()))) {
return EventStatus::Hidden; return EventStatus::Hidden;
}
return EventStatus::Normal; return EventStatus::Normal;
} }
if (role == EventIdRole) if (role == EventIdRole) {
return !evt.id().isEmpty() ? evt.id() : evt.transactionId(); return !evt.id().isEmpty() ? evt.id() : evt.transactionId();
if (role == LongOperationRole) {
if (auto e = eventCast<const RoomMessageEvent>(&evt))
if (e->hasFileContent())
return QVariant::fromValue(m_currentRoom->fileTransferInfo(e->id()));
} }
if (role == AnnotationRole) if (role == LongOperationRole) {
if (isPending) if (auto e = eventCast<const RoomMessageEvent>(&evt)) {
if (e->hasFileContent()) {
return QVariant::fromValue(m_currentRoom->fileTransferInfo(e->id()));
}
}
}
if (role == AnnotationRole) {
if (isPending) {
return pendingIt->annotation(); return pendingIt->annotation();
}
}
if (role == TimeRole || role == SectionRole) { if (role == TimeRole || role == SectionRole) {
auto ts = isPending ? pendingIt->lastUpdated() : makeMessageTimestamp(timelineIt); auto ts = isPending ? pendingIt->lastUpdated() : makeMessageTimestamp(timelineIt);
@@ -432,8 +462,9 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
QVariantList variantList; QVariantList variantList;
const auto users = m_currentRoom->usersAtEventId(evt.id()); const auto users = m_currentRoom->usersAtEventId(evt.id());
for (User *user : users) { for (User *user : users) {
if (user == m_currentRoom->localUser()) if (user == m_currentRoom->localUser()) {
continue; continue;
}
variantList.append(QVariant::fromValue(user)); variantList.append(QVariant::fromValue(user));
} }
return variantList; return variantList;
@@ -441,11 +472,13 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (role == ReplyRole) { if (role == ReplyRole) {
const QString &replyEventId = evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString(); const QString &replyEventId = evt.contentJson()["m.relates_to"].toObject()["m.in_reply_to"].toObject()["event_id"].toString();
if (replyEventId.isEmpty()) if (replyEventId.isEmpty()) {
return {}; return {};
};
const auto replyIt = m_currentRoom->findInTimeline(replyEventId); const auto replyIt = m_currentRoom->findInTimeline(replyEventId);
if (replyIt == m_currentRoom->timelineEdge()) if (replyIt == m_currentRoom->timelineEdge()) {
return {}; return {};
};
const auto &replyEvt = **replyIt; const auto &replyEvt = **replyIt;
return QVariantMap {{"eventId", replyEventId}, {"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)}, {"author", userAtEvent(static_cast<NeoChatUser *>(m_currentRoom->user(replyEvt.senderId())), m_currentRoom, evt)}}; return QVariantMap {{"eventId", replyEventId}, {"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)}, {"author", userAtEvent(static_cast<NeoChatUser *>(m_currentRoom->user(replyEvt.senderId())), m_currentRoom, evt)}};
@@ -477,14 +510,17 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
if (role == ReactionRole) { if (role == ReactionRole) {
const auto &annotations = m_currentRoom->relatedEvents(evt, EventRelation::Annotation()); const auto &annotations = m_currentRoom->relatedEvents(evt, EventRelation::Annotation());
if (annotations.isEmpty()) if (annotations.isEmpty()) {
return {}; return {};
};
QMap<QString, QList<NeoChatUser *>> reactions = {}; QMap<QString, QList<NeoChatUser *>> reactions = {};
for (const auto &a : annotations) { for (const auto &a : annotations) {
if (a->isRedacted()) // Just in case? if (a->isRedacted()) { // Just in case?
continue; continue;
if (auto e = eventCast<const ReactionEvent>(a)) }
if (auto e = eventCast<const ReactionEvent>(a)) {
reactions[e->relation().key].append(static_cast<NeoChatUser *>(m_currentRoom->user(e->senderId()))); reactions[e->relation().key].append(static_cast<NeoChatUser *>(m_currentRoom->user(e->senderId())));
}
} }
if (reactions.isEmpty()) { if (reactions.isEmpty()) {

View File

@@ -55,17 +55,17 @@ public:
explicit MessageEventModel(QObject *parent = nullptr); explicit MessageEventModel(QObject *parent = nullptr);
~MessageEventModel() override; ~MessageEventModel() override;
NeoChatRoom *room() const [[nodiscard]] NeoChatRoom *room() const
{ {
return m_currentRoom; return m_currentRoom;
} }
void setRoom(NeoChatRoom *room); void setRoom(NeoChatRoom *room);
int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE int eventIDToIndex(const QString &eventID) const; Q_INVOKABLE [[nodiscard]] int eventIDToIndex(const QString &eventID) const;
private Q_SLOTS: private Q_SLOTS:
int refreshEvent(const QString &eventId); int refreshEvent(const QString &eventId);
@@ -75,13 +75,13 @@ private:
NeoChatRoom *m_currentRoom = nullptr; NeoChatRoom *m_currentRoom = nullptr;
QString lastReadEventId; QString lastReadEventId;
int rowBelowInserted = -1; int rowBelowInserted = -1;
bool movingEvent = 0; bool movingEvent = false;
int timelineBaseIndex() const; [[nodiscard]] int timelineBaseIndex() const;
QDateTime makeMessageTimestamp(const Quotient::Room::rev_iter_t &baseIt) const; [[nodiscard]] QDateTime makeMessageTimestamp(const Quotient::Room::rev_iter_t &baseIt) const;
QString renderDate(QDateTime timestamp) const; [[nodiscard]] static QString renderDate(const QDateTime &timestamp);
void refreshLastUserEvents(int baseRow); void refreshLastUserEvents(int baseTimelineRow);
void refreshEventRoles(int row, const QVector<int> &roles = {}); void refreshEventRoles(int row, const QVector<int> &roles = {});
int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {}); int refreshEventRoles(const QString &eventId, const QVector<int> &roles = {});

View File

@@ -29,9 +29,9 @@
#include "events/roompowerlevelsevent.h" #include "events/roompowerlevelsevent.h"
#include "events/typingevent.h" #include "events/typingevent.h"
#include "jobs/downloadfilejob.h" #include "jobs/downloadfilejob.h"
#include "notificationsmanager.h"
#include "user.h" #include "user.h"
#include "utils.h" #include "utils.h"
#include "notificationsmanager.h"
#include <KLocalizedString> #include <KLocalizedString>
@@ -45,14 +45,17 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
setHasFileUploading(false); setHasFileUploading(false);
}); });
connect(this, &NeoChatRoom::notificationCountChanged, this, [this]() { connect(this, &NeoChatRoom::notificationCountChanged, this, [this]() {
if(messageEvents().size() == 0) if (messageEvents().size() == 0) {
return; return;
}
const RoomEvent *lastEvent = messageEvents().rbegin()->get(); const RoomEvent *lastEvent = messageEvents().rbegin()->get();
if (lastEvent->isStateEvent()) if (lastEvent->isStateEvent()) {
return; return;
}
User *sender = user(lastEvent->senderId()); User *sender = user(lastEvent->senderId());
if (sender == localUser()) if (sender == localUser()) {
return; return;
}
NotificationsManager::instance().postNotification(id(), lastEvent->id(), displayName(), sender->displayname(this), eventToString(*lastEvent), avatar(128)); NotificationsManager::instance().postNotification(id(), lastEvent->id(), displayName(), sender->displayname(this), eventToString(*lastEvent), avatar(128));
}); });
@@ -62,24 +65,25 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
void NeoChatRoom::uploadFile(const QUrl &url, const QString &body) void NeoChatRoom::uploadFile(const QUrl &url, const QString &body)
{ {
if (url.isEmpty()) if (url.isEmpty()) {
return; return;
}
QString txnId = postFile(body.isEmpty() ? url.fileName() : body, url, false); QString txnId = postFile(body.isEmpty() ? url.fileName() : body, url, false);
setHasFileUploading(true); setHasFileUploading(true);
connect(this, &Room::fileTransferCompleted, [=](QString id, QUrl /*localFile*/, QUrl /*mxcUrl*/) { connect(this, &Room::fileTransferCompleted, [=](const QString &id, const QUrl & /*localFile*/, const QUrl & /*mxcUrl*/) {
if (id == txnId) { if (id == txnId) {
setFileUploadingProgress(0); setFileUploadingProgress(0);
setHasFileUploading(false); setHasFileUploading(false);
} }
}); });
connect(this, &Room::fileTransferFailed, [=](QString id, QString /*error*/) { connect(this, &Room::fileTransferFailed, [=](const QString &id, const QString & /*error*/) {
if (id == txnId) { if (id == txnId) {
setFileUploadingProgress(0); setFileUploadingProgress(0);
setHasFileUploading(false); setHasFileUploading(false);
} }
}); });
connect(this, &Room::fileTransferProgress, [=](QString id, qint64 progress, qint64 total) { connect(this, &Room::fileTransferProgress, [=](const QString &id, qint64 progress, qint64 total) {
if (id == txnId) { if (id == txnId) {
qDebug() << "Progress:" << progress << total; qDebug() << "Progress:" << progress << total;
setFileUploadingProgress(int(float(progress) / float(total) * 100)); setFileUploadingProgress(int(float(progress) / float(total) * 100));
@@ -118,13 +122,16 @@ QString NeoChatRoom::lastEvent() const
for (auto i = messageEvents().rbegin(); i < messageEvents().rend(); i++) { for (auto i = messageEvents().rbegin(); i < messageEvents().rend(); i++) {
const RoomEvent *evt = i->get(); const RoomEvent *evt = i->get();
if (is<RedactionEvent>(*evt) || is<ReactionEvent>(*evt)) if (is<RedactionEvent>(*evt) || is<ReactionEvent>(*evt)) {
continue; continue;
if (evt->isRedacted()) }
if (evt->isRedacted()) {
continue; continue;
}
if (evt->isStateEvent() && static_cast<const StateEventBase &>(*evt).repeatsState()) if (evt->isStateEvent() && static_cast<const StateEventBase &>(*evt).repeatsState()) {
continue; continue;
}
if (auto e = eventCast<const RoomMessageEvent>(evt)) { if (auto e = eventCast<const RoomMessageEvent>(evt)) {
if (!e->replacedEvent().isEmpty() && e->replacedEvent() != e->id()) { if (!e->replacedEvent().isEmpty() && e->replacedEvent() != e->id()) {
@@ -132,8 +139,9 @@ QString NeoChatRoom::lastEvent() const
} }
} }
if (connection()->isIgnored(user(evt->senderId()))) if (connection()->isIgnored(user(evt->senderId()))) {
continue; continue;
}
return user(evt->senderId())->displayname() + (evt->isStateEvent() ? " " : ": ") + eventToString(*evt); return user(evt->senderId())->displayname() + (evt->isStateEvent() ? " " : ": ") + eventToString(*evt);
} }
@@ -148,12 +156,14 @@ bool NeoChatRoom::isEventHighlighted(const RoomEvent *e) const
void NeoChatRoom::checkForHighlights(const Quotient::TimelineItem &ti) void NeoChatRoom::checkForHighlights(const Quotient::TimelineItem &ti)
{ {
auto localUserId = localUser()->id(); auto localUserId = localUser()->id();
if (ti->senderId() == localUserId) if (ti->senderId() == localUserId) {
return; return;
}
if (auto *e = ti.viewAs<RoomMessageEvent>()) { if (auto *e = ti.viewAs<RoomMessageEvent>()) {
const auto &text = e->plainBody(); const auto &text = e->plainBody();
if (text.contains(localUserId) || text.contains(roomMembername(localUserId))) if (text.contains(localUserId) || text.contains(roomMembername(localUserId))) {
highlights.insert(e); highlights.insert(e);
}
} }
} }
@@ -190,8 +200,9 @@ void NeoChatRoom::countChanged()
QDateTime NeoChatRoom::lastActiveTime() const QDateTime NeoChatRoom::lastActiveTime() const
{ {
if (timelineSize() == 0) if (timelineSize() == 0) {
return QDateTime(); return QDateTime();
}
return messageEvents().rbegin()->get()->originTimestamp(); return messageEvents().rbegin()->get()->originTimestamp();
} }
@@ -207,8 +218,9 @@ int NeoChatRoom::savedBottomVisibleIndex() const
void NeoChatRoom::saveViewport(int topIndex, int bottomIndex) void NeoChatRoom::saveViewport(int topIndex, int bottomIndex)
{ {
if (topIndex == -1 || bottomIndex == -1 || (bottomIndex == savedBottomVisibleIndex() && (bottomIndex == 0 || topIndex == savedTopVisibleIndex()))) if (topIndex == -1 || bottomIndex == -1 || (bottomIndex == savedBottomVisibleIndex() && (bottomIndex == 0 || topIndex == savedTopVisibleIndex()))) {
return; return;
}
if (bottomIndex == 0) { if (bottomIndex == 0) {
setFirstDisplayedEventId({}); setFirstDisplayedEventId({});
setLastDisplayedEventId({}); setLastDisplayedEventId({});
@@ -222,15 +234,16 @@ QVariantList NeoChatRoom::getUsers(const QString &keyword) const
{ {
const auto userList = users(); const auto userList = users();
QVariantList matchedList; QVariantList matchedList;
for (const auto u : userList) for (const auto u : userList) {
if (u->displayname(this).contains(keyword, Qt::CaseInsensitive)) { if (u->displayname(this).contains(keyword, Qt::CaseInsensitive)) {
matchedList.append(QVariant::fromValue(u)); matchedList.append(QVariant::fromValue(u));
} }
}
return matchedList; return matchedList;
} }
QUrl NeoChatRoom::urlToMxcUrl(QUrl mxcUrl) QUrl NeoChatRoom::urlToMxcUrl(const QUrl &mxcUrl)
{ {
return DownloadFileJob::makeRequestUrl(connection()->homeserver(), mxcUrl); return DownloadFileJob::makeRequestUrl(connection()->homeserver(), mxcUrl);
} }
@@ -268,7 +281,7 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
if (removeReply) { if (removeReply) {
htmlBody.remove(utils::removeRichReplyRegex); htmlBody.remove(utils::removeRichReplyRegex);
} }
htmlBody.replace(utils::userPillRegExp, "<b class=\"user-pill\">\\1</b>"); htmlBody.replace(utils::userPillRegExp, R"(<b class="user-pill">\1</b>)");
htmlBody.replace(utils::strikethroughRegExp, "<s>\\1</s>"); htmlBody.replace(utils::strikethroughRegExp, "<s>\\1</s>");
return htmlBody; return htmlBody;
@@ -309,30 +322,35 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
// The below code assumes senderName output in AuthorRole // The below code assumes senderName output in AuthorRole
switch (e.membership()) { switch (e.membership()) {
case MembershipType::Invite: case MembershipType::Invite:
if (e.repeatsState()) if (e.repeatsState()) {
return i18n("reinvited %1 to the room", subjectName); return i18n("reinvited %1 to the room", subjectName);
}
case MembershipType::Join: { case MembershipType::Join: {
if (e.repeatsState()) if (e.repeatsState()) {
return i18n("joined the room (repeated)"); return i18n("joined the room (repeated)");
}
if (!e.prevContent() || e.membership() != e.prevContent()->membership) { if (!e.prevContent() || e.membership() != e.prevContent()->membership) {
return e.membership() == MembershipType::Invite ? i18n("invited %1 to the room", subjectName) : i18n("joined the room"); return e.membership() == MembershipType::Invite ? i18n("invited %1 to the room", subjectName) : i18n("joined the room");
} }
QString text {}; QString text {};
if (e.isRename()) { if (e.isRename()) {
if (e.displayName().isEmpty()) if (e.displayName().isEmpty()) {
text = i18n("cleared their display name"); text = i18n("cleared their display name");
else } else {
text = i18n("changed their display name to %1", e.displayName().toHtmlEscaped()); text = i18n("changed their display name to %1", e.displayName().toHtmlEscaped());
}
} }
if (e.isAvatarUpdate()) { if (e.isAvatarUpdate()) {
if (!text.isEmpty()) if (!text.isEmpty()) {
text += i18n(" and "); text += i18n(" and ");
if (e.avatarUrl().isEmpty()) }
if (e.avatarUrl().isEmpty()) {
text += i18n("cleared their avatar"); text += i18n("cleared their avatar");
else if (e.prevContent()->avatarUrl.isEmpty()) } else if (e.prevContent()->avatarUrl.isEmpty()) {
text += i18n("set an avatar"); text += i18n("set an avatar");
else } else {
text += i18n("updated their avatar"); text += i18n("updated their avatar");
}
} }
return text; return text;
} }
@@ -378,7 +396,7 @@ QString NeoChatRoom::eventToString(const RoomEvent &evt, Qt::TextFormat format,
i18n("Unknown event")); i18n("Unknown event"));
} }
void NeoChatRoom::changeAvatar(QUrl localFile) void NeoChatRoom::changeAvatar(const QUrl &localFile)
{ {
const auto job = connection()->uploadFile(localFile.toLocalFile()); const auto job = connection()->uploadFile(localFile.toLocalFile());
if (isJobRunning(job)) { if (isJobRunning(job)) {
@@ -391,8 +409,9 @@ void NeoChatRoom::changeAvatar(QUrl localFile)
void NeoChatRoom::addLocalAlias(const QString &alias) void NeoChatRoom::addLocalAlias(const QString &alias)
{ {
auto a = aliases(); auto a = aliases();
if (a.contains(alias)) if (a.contains(alias)) {
return; return;
}
a += alias; a += alias;
@@ -402,8 +421,9 @@ void NeoChatRoom::addLocalAlias(const QString &alias)
void NeoChatRoom::removeLocalAlias(const QString &alias) void NeoChatRoom::removeLocalAlias(const QString &alias)
{ {
auto a = aliases(); auto a = aliases();
if (!a.contains(alias)) if (!a.contains(alias)) {
return; return;
}
a.removeAll(alias); a.removeAll(alias);
@@ -467,8 +487,9 @@ void NeoChatRoom::postPlainMessage(const QString &text, MessageEventType type, c
{ {
bool isReply = !replyEventId.isEmpty(); bool isReply = !replyEventId.isEmpty();
const auto replyIt = findInTimeline(replyEventId); const auto replyIt = findInTimeline(replyEventId);
if (replyIt == timelineEdge()) if (replyIt == timelineEdge()) {
isReply = false; isReply = false;
}
if (isReply) { if (isReply) {
const auto &replyEvt = **replyIt; const auto &replyEvt = **replyIt;
@@ -511,8 +532,9 @@ void NeoChatRoom::postHtmlMessage(const QString &text, const QString &html, Mess
{ {
bool isReply = !replyEventId.isEmpty(); bool isReply = !replyEventId.isEmpty();
const auto replyIt = findInTimeline(replyEventId); const auto replyIt = findInTimeline(replyEventId);
if (replyIt == timelineEdge()) if (replyIt == timelineEdge()) {
isReply = false; isReply = false;
}
if (isReply) { if (isReply) {
const auto &replyEvt = **replyIt; const auto &replyEvt = **replyIt;
@@ -553,12 +575,14 @@ void NeoChatRoom::postHtmlMessage(const QString &text, const QString &html, Mess
void NeoChatRoom::toggleReaction(const QString &eventId, const QString &reaction) void NeoChatRoom::toggleReaction(const QString &eventId, const QString &reaction)
{ {
if (eventId.isEmpty() || reaction.isEmpty()) if (eventId.isEmpty() || reaction.isEmpty()) {
return; return;
}
const auto eventIt = findInTimeline(eventId); const auto eventIt = findInTimeline(eventId);
if (eventIt == timelineEdge()) if (eventIt == timelineEdge()) {
return; return;
}
const auto &evt = **eventIt; const auto &evt = **eventIt;
@@ -568,8 +592,9 @@ void NeoChatRoom::toggleReaction(const QString &eventId, const QString &reaction
if (!annotations.isEmpty()) { if (!annotations.isEmpty()) {
for (const auto &a : annotations) { for (const auto &a : annotations) {
if (auto e = eventCast<const ReactionEvent>(a)) { if (auto e = eventCast<const ReactionEvent>(a)) {
if (e->relation().key != reaction) if (e->relation().key != reaction) {
continue; continue;
}
if (e->senderId() == localUser()->id()) { if (e->senderId() == localUser()->id()) {
redactEventIds.push_back(e->id()); redactEventIds.push_back(e->id());
@@ -588,12 +613,13 @@ void NeoChatRoom::toggleReaction(const QString &eventId, const QString &reaction
} }
} }
bool NeoChatRoom::containsUser(QString userID) const bool NeoChatRoom::containsUser(const QString &userID) const
{ {
auto u = Room::user(userID); auto u = Room::user(userID);
if (!u) if (!u) {
return false; return false;
}
return Room::memberJoinState(u) != JoinState::Leave; return Room::memberJoinState(u) != JoinState::Leave;
} }

View File

@@ -35,14 +35,14 @@ class NeoChatRoom : public Room
public: public:
explicit NeoChatRoom(Connection *connection, QString roomId, JoinState joinState = {}); explicit NeoChatRoom(Connection *connection, QString roomId, JoinState joinState = {});
QVariantList getUsersTyping() const; [[nodiscard]] QVariantList getUsersTyping() const;
QString lastEvent() const; [[nodiscard]] QString lastEvent() const;
bool isEventHighlighted(const Quotient::RoomEvent *e) const; bool isEventHighlighted(const Quotient::RoomEvent *e) const;
QDateTime lastActiveTime() const; [[nodiscard]] QDateTime lastActiveTime() const;
bool hasFileUploading() const [[nodiscard]] bool hasFileUploading() const
{ {
return m_hasFileUploading; return m_hasFileUploading;
} }
@@ -55,7 +55,7 @@ public:
Q_EMIT hasFileUploadingChanged(); Q_EMIT hasFileUploadingChanged();
} }
int fileUploadingProgress() const [[nodiscard]] int fileUploadingProgress() const
{ {
return m_fileUploadingProgress; return m_fileUploadingProgress;
} }
@@ -68,24 +68,24 @@ public:
Q_EMIT fileUploadingProgressChanged(); Q_EMIT fileUploadingProgressChanged();
} }
bool readMarkerLoaded() const; [[nodiscard]] bool readMarkerLoaded() const;
Q_INVOKABLE int savedTopVisibleIndex() const; Q_INVOKABLE [[nodiscard]] int savedTopVisibleIndex() const;
Q_INVOKABLE int savedBottomVisibleIndex() const; Q_INVOKABLE [[nodiscard]] int savedBottomVisibleIndex() const;
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex); Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
Q_INVOKABLE QVariantList getUsers(const QString &keyword) const; Q_INVOKABLE [[nodiscard]] QVariantList getUsers(const QString &keyword) const;
Q_INVOKABLE QUrl urlToMxcUrl(QUrl mxcUrl); Q_INVOKABLE QUrl urlToMxcUrl(const QUrl &mxcUrl);
QString avatarMediaId() const; [[nodiscard]] QString avatarMediaId() const;
QString eventToString(const RoomEvent &evt, Qt::TextFormat format = Qt::PlainText, bool removeReply = true) const; [[nodiscard]] QString eventToString(const RoomEvent &evt, Qt::TextFormat format = Qt::PlainText, bool removeReply = true) const;
Q_INVOKABLE bool containsUser(QString userID) const; Q_INVOKABLE [[nodiscard]] bool containsUser(const QString &userID) const;
Q_INVOKABLE bool canSendEvent(const QString &eventType) const; Q_INVOKABLE [[nodiscard]] bool canSendEvent(const QString &eventType) const;
Q_INVOKABLE bool canSendState(const QString &eventType) const; Q_INVOKABLE [[nodiscard]] bool canSendState(const QString &eventType) const;
private: private:
QString m_cachedInput; QString m_cachedInput;
@@ -100,7 +100,7 @@ private:
void onAddHistoricalTimelineEvents(rev_iter_t from) override; void onAddHistoricalTimelineEvents(rev_iter_t from) override;
void onRedaction(const RoomEvent &prevEvent, const RoomEvent &after) override; void onRedaction(const RoomEvent &prevEvent, const RoomEvent &after) override;
static QString markdownToHTML(const QString &plaintext); static QString markdownToHTML(const QString &markdown);
private Q_SLOTS: private Q_SLOTS:
void countChanged(); void countChanged();
@@ -121,7 +121,7 @@ public Q_SLOTS:
void postArbitaryMessage(const QString &text, Quotient::RoomMessageEvent::MsgType type, const QString &replyEventId); void postArbitaryMessage(const QString &text, Quotient::RoomMessageEvent::MsgType type, const QString &replyEventId);
void postPlainMessage(const QString &text, Quotient::RoomMessageEvent::MsgType type = Quotient::MessageEventType::Text, const QString &replyEventId = ""); void postPlainMessage(const QString &text, Quotient::RoomMessageEvent::MsgType type = Quotient::MessageEventType::Text, const QString &replyEventId = "");
void postHtmlMessage(const QString &text, const QString &html, Quotient::MessageEventType type = Quotient::MessageEventType::Text, const QString &replyEventId = ""); void postHtmlMessage(const QString &text, const QString &html, Quotient::MessageEventType type = Quotient::MessageEventType::Text, const QString &replyEventId = "");
void changeAvatar(QUrl localFile); void changeAvatar(const QUrl &localFile);
void addLocalAlias(const QString &alias); void addLocalAlias(const QString &alias);
void removeLocalAlias(const QString &alias); void removeLocalAlias(const QString &alias);
void toggleReaction(const QString &eventId, const QString &reaction); void toggleReaction(const QString &eventId, const QString &reaction);

View File

@@ -6,11 +6,12 @@
#include "neochatuser.h" #include "neochatuser.h"
#include <PlatformTheme> // Kirigami #include <PlatformTheme> // Kirigami
#include <utility>
#include "csapi/profile.h" #include "csapi/profile.h"
NeoChatUser::NeoChatUser(QString userId, Connection *connection) NeoChatUser::NeoChatUser(QString userId, Connection *connection)
: User(userId, connection) : User(std::move(userId), connection)
{ {
m_theme = static_cast<Kirigami::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::PlatformTheme>(this, true)); m_theme = static_cast<Kirigami::PlatformTheme *>(qmlAttachedPropertiesObject<Kirigami::PlatformTheme>(this, true));
Q_ASSERT(m_theme); Q_ASSERT(m_theme);
@@ -23,10 +24,11 @@ QColor NeoChatUser::color()
return m_color; return m_color;
} }
void NeoChatUser::setColor(QColor color) void NeoChatUser::setColor(const QColor &color)
{ {
if (m_color == color) if (m_color == color) {
return; return;
}
m_color = color; m_color = color;
emit colorChanged(m_color); emit colorChanged(m_color);

View File

@@ -26,10 +26,10 @@ public:
public Q_SLOTS: public Q_SLOTS:
QColor color(); QColor color();
void setColor(QColor color); void setColor(const QColor &color);
Q_SIGNALS: Q_SIGNALS:
void colorChanged(QColor color); void colorChanged(QColor _t1);
private: private:
Kirigami::PlatformTheme *m_theme = nullptr; Kirigami::PlatformTheme *m_theme = nullptr;

View File

@@ -19,7 +19,6 @@ NotificationsManager &NotificationsManager::instance()
return _instance; return _instance;
} }
NotificationsManager::NotificationsManager(QObject *parent) NotificationsManager::NotificationsManager(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
@@ -27,7 +26,7 @@ NotificationsManager::NotificationsManager(QObject *parent)
void NotificationsManager::postNotification(const QString &roomid, const QString &eventid, const QString &roomname, const QString &sender, const QString &text, const QImage &icon) void NotificationsManager::postNotification(const QString &roomid, const QString &eventid, const QString &roomname, const QString &sender, const QString &text, const QImage &icon)
{ {
if(!NeoChatConfig::self()->showNotifications()) { if (!NeoChatConfig::self()->showNotifications()) {
return; return;
} }

View File

@@ -12,8 +12,9 @@ PublicRoomListModel::PublicRoomListModel(QObject *parent)
void PublicRoomListModel::setConnection(Connection *conn) void PublicRoomListModel::setConnection(Connection *conn)
{ {
if (m_connection == conn) if (m_connection == conn) {
return; return;
}
beginResetModel(); beginResetModel();
@@ -46,8 +47,9 @@ void PublicRoomListModel::setConnection(Connection *conn)
void PublicRoomListModel::setServer(const QString &value) void PublicRoomListModel::setServer(const QString &value)
{ {
if (m_server == value) if (m_server == value) {
return; return;
}
m_server = value; m_server = value;
@@ -74,8 +76,9 @@ void PublicRoomListModel::setServer(const QString &value)
void PublicRoomListModel::setKeyword(const QString &value) void PublicRoomListModel::setKeyword(const QString &value)
{ {
if (m_keyword == value) if (m_keyword == value) {
return; return;
}
m_keyword = value; m_keyword = value;
@@ -102,8 +105,9 @@ void PublicRoomListModel::setKeyword(const QString &value)
void PublicRoomListModel::next(int count) void PublicRoomListModel::next(int count)
{ {
if (count < 1) if (count < 1) {
return; return;
}
if (job) { if (job) {
qDebug() << "PublicRoomListModel: Other jobs running, ignore"; qDebug() << "PublicRoomListModel: Other jobs running, ignore";
@@ -134,8 +138,9 @@ void PublicRoomListModel::next(int count)
QVariant PublicRoomListModel::data(const QModelIndex &index, int role) const QVariant PublicRoomListModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid()) {
return QVariant(); return QVariant();
}
if (index.row() >= rooms.count()) { if (index.row() >= rooms.count()) {
qDebug() << "PublicRoomListModel, something's wrong: index.row() >= " qDebug() << "PublicRoomListModel, something's wrong: index.row() >= "
@@ -195,8 +200,9 @@ QVariant PublicRoomListModel::data(const QModelIndex &index, int role) const
return room.worldReadable; return room.worldReadable;
} }
if (role == IsJoinedRole) { if (role == IsJoinedRole) {
if (!m_connection) if (!m_connection) {
return {}; return {};
}
return m_connection->room(room.roomId, JoinState::Join) != nullptr; return m_connection->room(room.roomId, JoinState::Join) != nullptr;
} }
@@ -223,8 +229,9 @@ QHash<int, QByteArray> PublicRoomListModel::roleNames() const
int PublicRoomListModel::rowCount(const QModelIndex &parent) const int PublicRoomListModel::rowCount(const QModelIndex &parent) const
{ {
if (parent.isValid()) if (parent.isValid()) {
return 0; return 0;
}
return rooms.count(); return rooms.count();
} }

View File

@@ -38,30 +38,30 @@ public:
PublicRoomListModel(QObject *parent = nullptr); PublicRoomListModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = NameRole) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = NameRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Connection *connection() const [[nodiscard]] Connection *connection() const
{ {
return m_connection; return m_connection;
} }
void setConnection(Connection *value); void setConnection(Connection *conn);
QString server() const [[nodiscard]] QString server() const
{ {
return m_server; return m_server;
} }
void setServer(const QString &value); void setServer(const QString &value);
QString keyword() const [[nodiscard]] QString keyword() const
{ {
return m_keyword; return m_keyword;
} }
void setKeyword(const QString &value); void setKeyword(const QString &value);
bool hasMore() const; [[nodiscard]] bool hasMore() const;
Q_INVOKABLE void next(int count = 50); Q_INVOKABLE void next(int count = 50);

View File

@@ -5,9 +5,9 @@
*/ */
#include "roomlistmodel.h" #include "roomlistmodel.h"
#include "neochatconfig.h"
#include "user.h" #include "user.h"
#include "utils.h" #include "utils.h"
#include "neochatconfig.h"
#include "events/roomevent.h" #include "events/roomevent.h"
@@ -17,6 +17,7 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <KLocalizedString> #include <KLocalizedString>
#include <utility>
RoomListModel::RoomListModel(QObject *parent) RoomListModel::RoomListModel(QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
@@ -27,16 +28,16 @@ RoomListModel::RoomListModel(QObject *parent)
} }
} }
RoomListModel::~RoomListModel() RoomListModel::~RoomListModel() = default;
{
}
void RoomListModel::setConnection(Connection *connection) void RoomListModel::setConnection(Connection *connection)
{ {
if (connection == m_connection) if (connection == m_connection) {
return; return;
if (m_connection) }
if (m_connection) {
m_connection->disconnect(this); m_connection->disconnect(this);
}
if (!connection) { if (!connection) {
qDebug() << "Removing current connection..."; qDebug() << "Removing current connection...";
m_connection = nullptr; m_connection = nullptr;
@@ -61,13 +62,14 @@ void RoomListModel::setConnection(Connection *connection)
auto refreshRooms = [this, &connection](Quotient::DirectChatsMap rooms) { auto refreshRooms = [this, &connection](Quotient::DirectChatsMap rooms) {
for (const QString &roomID : qAsConst(rooms)) { for (const QString &roomID : qAsConst(rooms)) {
auto room = connection->room(roomID); auto room = connection->room(roomID);
if (room) if (room) {
refresh(static_cast<NeoChatRoom *>(room)); refresh(static_cast<NeoChatRoom *>(room));
}
} }
}; };
refreshRooms(additions); refreshRooms(std::move(additions));
refreshRooms(removals); refreshRooms(std::move(removals));
}); });
doResetModel(); doResetModel();
@@ -128,29 +130,37 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room)
refresh(room, {LastEventRole}); refresh(room, {LastEventRole});
}); });
connect(room, &Room::notificationCountChanged, this, [=] { connect(room, &Room::notificationCountChanged, this, [=] {
if (room->notificationCount() == 0) if (room->notificationCount() == 0) {
return; return;
if (room->timelineSize() == 0) }
if (room->timelineSize() == 0) {
return; return;
}
const RoomEvent *lastEvent = room->messageEvents().rbegin()->get(); const RoomEvent *lastEvent = room->messageEvents().rbegin()->get();
if (lastEvent->isStateEvent()) if (lastEvent->isStateEvent()) {
return; return;
}
User *sender = room->user(lastEvent->senderId()); User *sender = room->user(lastEvent->senderId());
if (sender == room->localUser()) if (sender == room->localUser()) {
return; return;
}
Q_EMIT newMessage(room->id(), lastEvent->id(), room->displayName(), sender->displayname(), room->eventToString(*lastEvent), room->avatar(128)); Q_EMIT newMessage(room->id(), lastEvent->id(), room->displayName(), sender->displayname(), room->eventToString(*lastEvent), room->avatar(128));
}); });
connect(room, &Room::highlightCountChanged, this, [=] { connect(room, &Room::highlightCountChanged, this, [=] {
if (room->highlightCount() == 0) if (room->highlightCount() == 0) {
return; return;
if (room->timelineSize() == 0) }
if (room->timelineSize() == 0) {
return; return;
}
const RoomEvent *lastEvent = room->messageEvents().rbegin()->get(); const RoomEvent *lastEvent = room->messageEvents().rbegin()->get();
if (lastEvent->isStateEvent()) if (lastEvent->isStateEvent()) {
return; return;
}
User *sender = room->user(lastEvent->senderId()); User *sender = room->user(lastEvent->senderId());
if (sender == room->localUser()) if (sender == room->localUser()) {
return; return;
}
Q_EMIT newHighlight(room->id(), lastEvent->id(), room->displayName(), sender->displayname(), room->eventToString(*lastEvent), room->avatar(128)); Q_EMIT newHighlight(room->id(), lastEvent->id(), room->displayName(), sender->displayname(), room->eventToString(*lastEvent), room->avatar(128));
}); });
connect(room, &Room::notificationCountChanged, this, &RoomListModel::refreshNotificationCount); connect(room, &Room::notificationCountChanged, this, &RoomListModel::refreshNotificationCount);
@@ -206,8 +216,9 @@ void RoomListModel::deleteRoom(Room *room)
{ {
qDebug() << "Deleting room" << room->id(); qDebug() << "Deleting room" << room->id();
const auto it = std::find(m_rooms.begin(), m_rooms.end(), room); const auto it = std::find(m_rooms.begin(), m_rooms.end(), room);
if (it == m_rooms.end()) if (it == m_rooms.end()) {
return; // Already deleted, nothing to do return; // Already deleted, nothing to do
}
qDebug() << "Erasing room" << room->id(); qDebug() << "Erasing room" << room->id();
const int row = it - m_rooms.begin(); const int row = it - m_rooms.begin();
beginRemoveRows(QModelIndex(), row, row); beginRemoveRows(QModelIndex(), row, row);
@@ -217,57 +228,74 @@ void RoomListModel::deleteRoom(Room *room)
int RoomListModel::rowCount(const QModelIndex &parent) const int RoomListModel::rowCount(const QModelIndex &parent) const
{ {
if (parent.isValid()) if (parent.isValid()) {
return 0; return 0;
}
return m_rooms.count(); return m_rooms.count();
} }
QVariant RoomListModel::data(const QModelIndex &index, int role) const QVariant RoomListModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid()) {
return QVariant(); return QVariant();
}
if (index.row() >= m_rooms.count()) { if (index.row() >= m_rooms.count()) {
qDebug() << "UserListModel: something wrong here..."; qDebug() << "UserListModel: something wrong here...";
return QVariant(); return QVariant();
} }
NeoChatRoom *room = m_rooms.at(index.row()); NeoChatRoom *room = m_rooms.at(index.row());
if (role == NameRole) if (role == NameRole) {
return room->displayName(); return room->displayName();
if (role == AvatarRole) }
if (role == AvatarRole) {
return room->avatarMediaId(); return room->avatarMediaId();
if (role == TopicRole) }
if (role == TopicRole) {
return room->topic(); return room->topic();
}
if (role == CategoryRole) { if (role == CategoryRole) {
if (room->joinState() == JoinState::Invite) if (room->joinState() == JoinState::Invite) {
return RoomType::Invited; return RoomType::Invited;
if (room->isFavourite()) }
if (room->isFavourite()) {
return RoomType::Favorite; return RoomType::Favorite;
if (room->isDirectChat()) }
if (room->isDirectChat()) {
return RoomType::Direct; return RoomType::Direct;
if (room->isLowPriority()) }
if (room->isLowPriority()) {
return RoomType::Deprioritized; return RoomType::Deprioritized;
}
return RoomType::Normal; return RoomType::Normal;
} }
if (role == UnreadCountRole) if (role == UnreadCountRole) {
return room->unreadCount(); return room->unreadCount();
if (role == NotificationCountRole) }
if (role == NotificationCountRole) {
return room->notificationCount(); return room->notificationCount();
if (role == HighlightCountRole) }
if (role == HighlightCountRole) {
return room->highlightCount(); return room->highlightCount();
if (role == LastEventRole) }
if (role == LastEventRole) {
return room->lastEvent(); return room->lastEvent();
if (role == LastActiveTimeRole) }
if (role == LastActiveTimeRole) {
return room->lastActiveTime(); return room->lastActiveTime();
}
if (role == JoinStateRole) { if (role == JoinStateRole) {
if (!room->successorId().isEmpty()) if (!room->successorId().isEmpty()) {
return QStringLiteral("upgraded"); return QStringLiteral("upgraded");
}
return toCString(room->joinState()); return toCString(room->joinState());
} }
if (role == CurrentRoomRole) if (role == CurrentRoomRole) {
return QVariant::fromValue(room); return QVariant::fromValue(room);
if (role == CategoryVisibleRole) }
if (role == CategoryVisibleRole) {
return m_categoryVisibility.value(data(index, CategoryRole).toInt(), true); return m_categoryVisibility.value(data(index, CategoryRole).toInt(), true);
}
return QVariant(); return QVariant();
} }
@@ -300,7 +328,7 @@ QHash<int, QByteArray> RoomListModel::roleNames() const
return roles; return roles;
} }
QString RoomListModel::categoryName(int section) const QString RoomListModel::categoryName(int section)
{ {
switch (section) { switch (section) {
case 1: case 1:

View File

@@ -54,27 +54,27 @@ public:
Q_ENUM(EventRoles) Q_ENUM(EventRoles)
RoomListModel(QObject *parent = nullptr); RoomListModel(QObject *parent = nullptr);
virtual ~RoomListModel() override; ~RoomListModel() override;
Connection *connection() const [[nodiscard]] Connection *connection() const
{ {
return m_connection; return m_connection;
} }
void setConnection(Connection *connection); void setConnection(Connection *connection);
void doResetModel(); void doResetModel();
Q_INVOKABLE NeoChatRoom *roomAt(int row) const; Q_INVOKABLE [[nodiscard]] NeoChatRoom *roomAt(int row) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override; Q_INVOKABLE [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE QString categoryName(int category) const; Q_INVOKABLE [[nodiscard]] static QString categoryName(int section);
Q_INVOKABLE void setCategoryVisible(int category, bool visible); Q_INVOKABLE void setCategoryVisible(int category, bool visible);
Q_INVOKABLE bool categoryVisible(int category) const; Q_INVOKABLE [[nodiscard]] bool categoryVisible(int category) const;
int notificationCount() const [[nodiscard]] int notificationCount() const
{ {
return m_notificationCount; return m_notificationCount;
} }
@@ -100,9 +100,9 @@ Q_SIGNALS:
void connectionChanged(); void connectionChanged();
void notificationCountChanged(); void notificationCountChanged();
void roomAdded(NeoChatRoom *room); void roomAdded(NeoChatRoom *_t1);
void newMessage(const QString &roomId, const QString &eventId, const QString &roomName, const QString &senderName, const QString &text, const QImage &icon); void newMessage(const QString &_t1, const QString &_t2, const QString &_t3, const QString &_t4, const QString &_t5, const QImage &_t6);
void newHighlight(const QString &roomId, const QString &eventId, const QString &roomName, const QString &senderName, const QString &text, const QImage &icon); void newHighlight(const QString &_t1, const QString &_t2, const QString &_t3, const QString &_t4, const QString &_t5, const QImage &_t6);
}; };
#endif // ROOMLISTMODEL_H #endif // ROOMLISTMODEL_H

View File

@@ -22,10 +22,11 @@ void SortFilterRoomListModel::setRoomSortOrder(SortFilterRoomListModel::RoomSort
{ {
m_sortOrder = sortOrder; m_sortOrder = sortOrder;
Q_EMIT roomSortOrderChanged(); Q_EMIT roomSortOrderChanged();
if (sortOrder == SortFilterRoomListModel::Alphabetical) if (sortOrder == SortFilterRoomListModel::Alphabetical) {
setSortRole(RoomListModel::NameRole); setSortRole(RoomListModel::NameRole);
else if (sortOrder == SortFilterRoomListModel::LastActivity) } else if (sortOrder == SortFilterRoomListModel::LastActivity) {
setSortRole(RoomListModel::LastActiveTimeRole); setSortRole(RoomListModel::LastActiveTimeRole);
}
invalidate(); invalidate();
} }
@@ -43,7 +44,8 @@ bool SortFilterRoomListModel::lessThan(const QModelIndex &source_left, const QMo
if (categoryLeft == RoomType::Types::Favorite && categoryRight == RoomType::Types::Favorite) { if (categoryLeft == RoomType::Types::Favorite && categoryRight == RoomType::Types::Favorite) {
return sourceModel()->data(source_left, RoomListModel::LastActiveTimeRole).toDateTime() > sourceModel()->data(source_right, RoomListModel::LastActiveTimeRole).toDateTime(); return sourceModel()->data(source_left, RoomListModel::LastActiveTimeRole).toDateTime() > sourceModel()->data(source_right, RoomListModel::LastActiveTimeRole).toDateTime();
} else if (categoryLeft == RoomType::Types::Favorite) { }
if (categoryLeft == RoomType::Types::Favorite) {
return true; return true;
} else if (categoryRight == RoomType::Types::Favorite) { } else if (categoryRight == RoomType::Types::Favorite) {
return false; return false;
@@ -51,10 +53,12 @@ bool SortFilterRoomListModel::lessThan(const QModelIndex &source_left, const QMo
return sourceModel()->data(source_left, RoomListModel::LastActiveTimeRole).toDateTime() > sourceModel()->data(source_right, RoomListModel::LastActiveTimeRole).toDateTime(); return sourceModel()->data(source_left, RoomListModel::LastActiveTimeRole).toDateTime() > sourceModel()->data(source_right, RoomListModel::LastActiveTimeRole).toDateTime();
} }
if (m_sortOrder != SortFilterRoomListModel::Categories) if (m_sortOrder != SortFilterRoomListModel::Categories) {
return QSortFilterProxyModel::lessThan(source_left, source_right); return QSortFilterProxyModel::lessThan(source_left, source_right);
if (sourceModel()->data(source_left, RoomListModel::CategoryRole) != sourceModel()->data(source_right, RoomListModel::CategoryRole)) }
if (sourceModel()->data(source_left, RoomListModel::CategoryRole) != sourceModel()->data(source_right, RoomListModel::CategoryRole)) {
return sourceModel()->data(source_left, RoomListModel::CategoryRole).toInt() < sourceModel()->data(source_right, RoomListModel::CategoryRole).toInt(); return sourceModel()->data(source_left, RoomListModel::CategoryRole).toInt() < sourceModel()->data(source_right, RoomListModel::CategoryRole).toInt();
}
return sourceModel()->data(source_left, RoomListModel::LastActiveTimeRole).toDateTime() > sourceModel()->data(source_right, RoomListModel::LastActiveTimeRole).toDateTime(); return sourceModel()->data(source_left, RoomListModel::LastActiveTimeRole).toDateTime() > sourceModel()->data(source_right, RoomListModel::LastActiveTimeRole).toDateTime();
} }

View File

@@ -26,15 +26,15 @@ public:
SortFilterRoomListModel(QObject *parent = nullptr); SortFilterRoomListModel(QObject *parent = nullptr);
void setRoomSortOrder(RoomSortOrder sortOrder); void setRoomSortOrder(RoomSortOrder sortOrder);
RoomSortOrder roomSortOrder() const; [[nodiscard]] RoomSortOrder roomSortOrder() const;
void setFilterText(const QString &text); void setFilterText(const QString &text);
QString filterText() const; [[nodiscard]] QString filterText() const;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; [[nodiscard]] bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
protected: protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; [[nodiscard]] bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
Q_SIGNALS: Q_SIGNALS:
void roomSortOrderChanged(); void roomSortOrderChanged();

View File

@@ -17,7 +17,7 @@ TrayIcon::TrayIcon(QObject *parent)
auto viewAction_ = new QAction(i18n("Show"), parent); auto viewAction_ = new QAction(i18n("Show"), parent);
connect(viewAction_, &QAction::triggered, this, &TrayIcon::showWindow); connect(viewAction_, &QAction::triggered, this, &TrayIcon::showWindow);
connect(this, &KStatusNotifierItem::activateRequested, this, [this] (bool active) { connect(this, &KStatusNotifierItem::activateRequested, this, [this](bool active) {
if (active) { if (active) {
Q_EMIT showWindow(); Q_EMIT showWindow();
} }

View File

@@ -8,12 +8,12 @@
// Modified from mujx/nheko's TrayIcon. // Modified from mujx/nheko's TrayIcon.
#include <KStatusNotifierItem>
#include <QAction> #include <QAction>
#include <QIcon> #include <QIcon>
#include <QIconEngine> #include <QIconEngine>
#include <QPainter> #include <QPainter>
#include <QRect> #include <QRect>
#include <KStatusNotifierItem>
class TrayIcon : public KStatusNotifierItem class TrayIcon : public KStatusNotifierItem
{ {
@@ -29,7 +29,7 @@ public:
} }
void setIconSource(const QString &source); void setIconSource(const QString &source);
bool isOnline() bool isOnline() const
{ {
return m_isOnline; return m_isOnline;
} }

View File

@@ -12,8 +12,9 @@ UserDirectoryListModel::UserDirectoryListModel(QObject *parent)
void UserDirectoryListModel::setConnection(Connection *conn) void UserDirectoryListModel::setConnection(Connection *conn)
{ {
if (m_connection == conn) if (m_connection == conn) {
return; return;
}
beginResetModel(); beginResetModel();
@@ -40,8 +41,9 @@ void UserDirectoryListModel::setConnection(Connection *conn)
void UserDirectoryListModel::setKeyword(const QString &value) void UserDirectoryListModel::setKeyword(const QString &value)
{ {
if (m_keyword == value) if (m_keyword == value) {
return; return;
}
m_keyword = value; m_keyword = value;
@@ -59,8 +61,9 @@ void UserDirectoryListModel::setKeyword(const QString &value)
void UserDirectoryListModel::search(int count) void UserDirectoryListModel::search(int count)
{ {
if (count < 1) if (count < 1) {
return; return;
}
if (job) { if (job) {
qDebug() << "UserDirectoryListModel: Other jobs running, ignore"; qDebug() << "UserDirectoryListModel: Other jobs running, ignore";
@@ -68,8 +71,9 @@ void UserDirectoryListModel::search(int count)
return; return;
} }
if (attempted) if (attempted) {
return; return;
}
job = m_connection->callApi<SearchUserDirectoryJob>(m_keyword, count); job = m_connection->callApi<SearchUserDirectoryJob>(m_keyword, count);
@@ -95,8 +99,9 @@ void UserDirectoryListModel::search(int count)
QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid()) {
return QVariant(); return QVariant();
}
if (index.row() >= users.count()) { if (index.row() >= users.count()) {
qDebug() << "UserDirectoryListModel, something's wrong: index.row() >= " qDebug() << "UserDirectoryListModel, something's wrong: index.row() >= "
@@ -130,8 +135,9 @@ QVariant UserDirectoryListModel::data(const QModelIndex &index, int role) const
return user.userId; return user.userId;
} }
if (role == DirectChatsRole) { if (role == DirectChatsRole) {
if (!m_connection) if (!m_connection) {
return {}; return {};
};
auto userObj = m_connection->user(user.userId); auto userObj = m_connection->user(user.userId);
auto directChats = m_connection->directChats(); auto directChats = m_connection->directChats();
@@ -161,8 +167,9 @@ QHash<int, QByteArray> UserDirectoryListModel::roleNames() const
int UserDirectoryListModel::rowCount(const QModelIndex &parent) const int UserDirectoryListModel::rowCount(const QModelIndex &parent) const
{ {
if (parent.isValid()) if (parent.isValid()) {
return 0; return 0;
}
return users.count(); return users.count();
} }

View File

@@ -31,24 +31,24 @@ public:
UserDirectoryListModel(QObject *parent = nullptr); UserDirectoryListModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role = NameRole) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = NameRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Connection *connection() const [[nodiscard]] Connection *connection() const
{ {
return m_connection; return m_connection;
} }
void setConnection(Connection *value); void setConnection(Connection *conn);
QString keyword() const [[nodiscard]] QString keyword() const
{ {
return m_keyword; return m_keyword;
} }
void setKeyword(const QString &value); void setKeyword(const QString &value);
bool limited() const [[nodiscard]] bool limited() const
{ {
return m_limited; return m_limited;
} }

View File

@@ -25,16 +25,18 @@ UserListModel::UserListModel(QObject *parent)
void UserListModel::setRoom(Quotient::Room *room) void UserListModel::setRoom(Quotient::Room *room)
{ {
if (m_currentRoom == room) if (m_currentRoom == room) {
return; return;
}
using namespace Quotient; using namespace Quotient;
beginResetModel(); beginResetModel();
if (m_currentRoom) { if (m_currentRoom) {
m_currentRoom->disconnect(this); m_currentRoom->disconnect(this);
// m_currentRoom->connection()->disconnect(this); // m_currentRoom->connection()->disconnect(this);
for (User *user : qAsConst(m_users)) for (User *user : qAsConst(m_users)) {
user->disconnect(this); user->disconnect(this);
}
m_users.clear(); m_users.clear();
} }
m_currentRoom = room; m_currentRoom = room;
@@ -61,15 +63,17 @@ void UserListModel::setRoom(Quotient::Room *room)
Quotient::User *UserListModel::userAt(QModelIndex index) const Quotient::User *UserListModel::userAt(QModelIndex index) const
{ {
if (index.row() < 0 || index.row() >= m_users.size()) if (index.row() < 0 || index.row() >= m_users.size()) {
return nullptr; return nullptr;
}
return m_users.at(index.row()); return m_users.at(index.row());
} }
QVariant UserListModel::data(const QModelIndex &index, int role) const QVariant UserListModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid()) {
return QVariant(); return QVariant();
}
if (index.row() >= m_users.count()) { if (index.row() >= m_users.count()) {
qDebug() << "UserListModel, something's wrong: index.row() >= m_users.count()"; qDebug() << "UserListModel, something's wrong: index.row() >= m_users.count()";
@@ -132,8 +136,9 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
int UserListModel::rowCount(const QModelIndex &parent) const int UserListModel::rowCount(const QModelIndex &parent) const
{ {
if (parent.isValid()) if (parent.isValid()) {
return 0; return 0;
}
return m_users.count(); return m_users.count();
} }
@@ -155,23 +160,26 @@ void UserListModel::userRemoved(Quotient::User *user)
m_users.removeAt(pos); m_users.removeAt(pos);
endRemoveRows(); endRemoveRows();
user->disconnect(this); user->disconnect(this);
} else } else {
qWarning() << "Trying to remove a room member not in the user list"; qWarning() << "Trying to remove a room member not in the user list";
}
} }
void UserListModel::refresh(Quotient::User *user, QVector<int> roles) void UserListModel::refresh(Quotient::User *user, const QVector<int> &roles)
{ {
auto pos = findUserPos(user); auto pos = findUserPos(user);
if (pos != m_users.size()) if (pos != m_users.size()) {
Q_EMIT dataChanged(index(pos), index(pos), roles); Q_EMIT dataChanged(index(pos), index(pos), roles);
else } else {
qWarning() << "Trying to access a room member not in the user list"; qWarning() << "Trying to access a room member not in the user list";
}
} }
void UserListModel::avatarChanged(Quotient::User *user, const Quotient::Room *context) void UserListModel::avatarChanged(Quotient::User *user, const Quotient::Room *context)
{ {
if(context == m_currentRoom) if (context == m_currentRoom) {
refresh(user, {AvatarRole}); refresh(user, {AvatarRole});
}
} }
int UserListModel::findUserPos(User *user) const int UserListModel::findUserPos(User *user) const

View File

@@ -48,17 +48,17 @@ public:
UserListModel(QObject *parent = nullptr); UserListModel(QObject *parent = nullptr);
Quotient::Room *room() const [[nodiscard]] Quotient::Room *room() const
{ {
return m_currentRoom; return m_currentRoom;
} }
void setRoom(Quotient::Room *room); void setRoom(Quotient::Room *room);
Quotient::User *userAt(QModelIndex index) const; [[nodiscard]] Quotient::User *userAt(QModelIndex index) const;
QVariant data(const QModelIndex &index, int role = NameRole) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = NameRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; [[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS: Q_SIGNALS:
void roomChanged(); void roomChanged();
@@ -66,7 +66,7 @@ Q_SIGNALS:
private Q_SLOTS: private Q_SLOTS:
void userAdded(Quotient::User *user); void userAdded(Quotient::User *user);
void userRemoved(Quotient::User *user); void userRemoved(Quotient::User *user);
void refresh(Quotient::User *user, QVector<int> roles = {}); void refresh(Quotient::User *user, const QVector<int> &roles = {});
void avatarChanged(Quotient::User *user, const Quotient::Room *context); void avatarChanged(Quotient::User *user, const Quotient::Room *context);
private: private:
@@ -74,7 +74,7 @@ private:
QList<Quotient::User *> m_users; QList<Quotient::User *> m_users;
int findUserPos(Quotient::User *user) const; int findUserPos(Quotient::User *user) const;
int findUserPos(const QString &username) const; [[nodiscard]] int findUserPos(const QString &username) const;
}; };
#endif // USERLISTMODEL_H #endif // USERLISTMODEL_H