diff --git a/CMakeLists.txt b/CMakeLists.txt index 828509471bc6f6b9902173f675d588f1a8c5e6ae..05e5438049f3d9dfef7aec8396ce34a8f6afe9c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,6 +326,7 @@ set(SRC_FILES src/UserInfoWidget.cpp src/UserSettingsPage.cpp src/UsersModel.cpp + src/RoomsModel.cpp src/Utils.cpp src/WebRTCSession.cpp src/WelcomePage.cpp @@ -537,6 +538,7 @@ qt5_wrap_cpp(MOC_HEADERS src/UserInfoWidget.h src/UserSettingsPage.h src/UsersModel.h + src/RoomsModel.h src/WebRTCSession.h src/WelcomePage.h src/popups/PopupItem.h diff --git a/resources/qml/Completer.qml b/resources/qml/Completer.qml index 27322172e2619e7471c36f33434729c1e85f4f49..f77f50e9bb07aac2a5fb755e16e64d5b464c69bc 100644 --- a/resources/qml/Completer.qml +++ b/resources/qml/Completer.qml @@ -154,6 +154,35 @@ Popup { } + DelegateChoice { + roleValue: "room" + + RowLayout { + id: del + + anchors.centerIn: parent + + Avatar { + height: 24 + width: 24 + url: model.avatarUrl.replace("mxc://", "image://MxcImage/") + onClicked: popup.completionClicked(completer.completionAt(model.index)) + } + + Label { + text: model.roomName + color: model.index == popup.currentIndex ? colors.highlightedText : colors.text + } + + Label { + text: "(" + model.roomAlias + ")" + color: model.index == popup.currentIndex ? colors.highlightedText : colors.buttonText + } + + } + + } + } } diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml index b5c966606299d78f99cde0c0316312e3ce592385..7ecaf81a5b2703cd4dde820cee9da1d4f8965e31 100644 --- a/resources/qml/MessageInput.qml +++ b/resources/qml/MessageInput.qml @@ -183,6 +183,9 @@ Rectangle { } else if (event.key == Qt.Key_Colon) { messageInput.openCompleter(cursorPosition, "emoji"); popup.open(); + } else if (event.key == Qt.Key_NumberSign) { + messageInput.openCompleter(cursorPosition, "room"); + popup.open(); } else if (event.key == Qt.Key_Escape && popup.opened) { completerTriggeredAt = -1; popup.completerName = ""; diff --git a/src/RoomsModel.cpp b/src/RoomsModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4286f87b54e20a6a84322a580fbbc6b1dcb3e271 --- /dev/null +++ b/src/RoomsModel.cpp @@ -0,0 +1,69 @@ +#include "RoomsModel.h" + +#include <QUrl> + +#include "Cache_p.h" +#include "CompletionModelRoles.h" + +RoomsModel::RoomsModel(bool showOnlyRoomWithAliases, QObject *parent) + : QAbstractListModel(parent) + , showOnlyRoomWithAliases_(showOnlyRoomWithAliases) +{ + std::vector<std::string> rooms_ = cache::joinedRooms(); + roomInfos = cache::getRoomInfo(rooms_); + + for (const auto &r : rooms_) { + auto roomAliasesList = cache::client()->getRoomAliases(r); + + if (showOnlyRoomWithAliases_) { + if (roomAliasesList && !roomAliasesList->alias.empty()) { + roomids.push_back(QString::fromStdString(r)); + roomAliases.push_back( + QString::fromStdString(roomAliasesList->alias)); + } + } else { + roomids.push_back(QString::fromStdString(r)); + roomAliases.push_back( + roomAliasesList ? QString::fromStdString(roomAliasesList->alias) : ""); + } + } +} + +QHash<int, QByteArray> +RoomsModel::roleNames() const +{ + return {{CompletionModel::CompletionRole, "completionRole"}, + {CompletionModel::SearchRole, "searchRole"}, + {CompletionModel::SearchRole2, "searchRole2"}, + {Roles::RoomAlias, "roomAlias"}, + {Roles::AvatarUrl, "avatarUrl"}, + {Roles::RoomID, "roomid"}, + {Roles::RoomName, "roomName"}}; +} + +QVariant +RoomsModel::data(const QModelIndex &index, int role) const +{ + if (hasIndex(index.row(), index.column(), index.parent())) { + switch (role) { + case CompletionModel::CompletionRole: { + QString percentEncoding = QUrl::toPercentEncoding(roomAliases[index.row()]); + return QString("[%1](https://matrix.to/#/%2)") + .arg(roomAliases[index.row()], percentEncoding); + } + case CompletionModel::SearchRole: + case Qt::DisplayRole: + case Roles::RoomAlias: + return roomAliases[index.row()]; + case CompletionModel::SearchRole2: + case Roles::RoomName: + return QString::fromStdString(roomInfos.at(roomids[index.row()]).name); + case Roles::AvatarUrl: + return QString::fromStdString( + roomInfos.at(roomids[index.row()]).avatar_url); + case Roles::RoomID: + return roomids[index.row()]; + } + } + return {}; +} diff --git a/src/RoomsModel.h b/src/RoomsModel.h new file mode 100644 index 0000000000000000000000000000000000000000..0e006448d88bf5eef5d11a3e72fa44144d17bd4a --- /dev/null +++ b/src/RoomsModel.h @@ -0,0 +1,33 @@ +#pragma once + +#include "Cache.h" + +#include <QAbstractListModel> +#include <QString> + +class RoomsModel : public QAbstractListModel +{ +public: + enum Roles + { + AvatarUrl = Qt::UserRole, + RoomAlias, + RoomID, + RoomName, + }; + + RoomsModel(bool showOnlyRoomWithAliases = false, QObject *parent = nullptr); + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + (void)parent; + return (int)roomids.size(); + } + QVariant data(const QModelIndex &index, int role) const override; + +private: + std::vector<QString> roomids; + std::vector<QString> roomAliases; + std::map<QString, RoomInfo> roomInfos; + bool showOnlyRoomWithAliases_; +}; diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index 08cbd15b0a3804ee914f1457dc977e3d46ee111e..5ef38ac7f1520641472a64810b37f092579bb06f 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -19,6 +19,7 @@ #include "MainWindow.h" #include "MatrixClient.h" #include "Olm.h" +#include "RoomsModel.h" #include "TimelineModel.h" #include "TimelineViewManager.h" #include "UserSettingsPage.h" @@ -186,6 +187,11 @@ InputBar::completerFor(QString completerName) auto proxy = new CompletionProxyModel(emojiModel); emojiModel->setParent(proxy); return proxy; + } else if (completerName == "room") { + auto roomModel = new RoomsModel(true); + auto proxy = new CompletionProxyModel(roomModel); + roomModel->setParent(proxy); + return proxy; } return nullptr; }