Some basic room list
This commit is contained in:
parent
567fe81ad7
commit
10fd2752f9
@ -272,6 +272,7 @@ set(SRC_FILES
|
|||||||
src/timeline/TimelineModel.cpp
|
src/timeline/TimelineModel.cpp
|
||||||
src/timeline/DelegateChooser.cpp
|
src/timeline/DelegateChooser.cpp
|
||||||
src/timeline/Permissions.cpp
|
src/timeline/Permissions.cpp
|
||||||
|
src/timeline/RoomlistModel.cpp
|
||||||
|
|
||||||
# UI components
|
# UI components
|
||||||
src/ui/Avatar.cpp
|
src/ui/Avatar.cpp
|
||||||
@ -497,6 +498,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||||||
src/timeline/TimelineModel.h
|
src/timeline/TimelineModel.h
|
||||||
src/timeline/DelegateChooser.h
|
src/timeline/DelegateChooser.h
|
||||||
src/timeline/Permissions.h
|
src/timeline/Permissions.h
|
||||||
|
src/timeline/RoomlistModel.h
|
||||||
|
|
||||||
# UI components
|
# UI components
|
||||||
src/ui/Avatar.h
|
src/ui/Avatar.h
|
||||||
|
28
resources/qml/ElidedLabel.qml
Normal file
28
resources/qml/ElidedLabel.qml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias fullText: metrics.text
|
||||||
|
property alias elideWidth: metrics.elideWidth
|
||||||
|
|
||||||
|
color: Nheko.colors.text
|
||||||
|
text: metrics.elidedText
|
||||||
|
maximumLineCount: 1
|
||||||
|
elide: Text.ElideRight
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: metrics
|
||||||
|
|
||||||
|
font.pointSize: root.font.pointSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,7 +21,7 @@ Popup {
|
|||||||
modal: true
|
modal: true
|
||||||
palette: Nheko.colors
|
palette: Nheko.colors
|
||||||
parent: Overlay.overlay
|
parent: Overlay.overlay
|
||||||
width: implicitWidth >= (timelineView.width * 0.8) ? implicitWidth : (timelineView.width * 0.8)
|
width: implicitWidth >= (timelineRoot.width * 0.8) ? implicitWidth : (timelineRoot.width * 0.8)
|
||||||
height: implicitHeight + completerPopup.height + padding * 2
|
height: implicitHeight + completerPopup.height + padding * 2
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 10
|
rightPadding: 10
|
||||||
|
@ -8,6 +8,132 @@ import QtQuick.Layouts 1.3
|
|||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
|
ListView {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: parent.height
|
||||||
|
model: Rooms
|
||||||
|
|
||||||
|
ScrollHelper {
|
||||||
|
flickable: parent
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: !Settings.mobileMode
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
color: Nheko.colors.window
|
||||||
|
height: fontMetrics.lineSpacing * 2.5 + Nheko.paddingMedium * 2
|
||||||
|
width: ListView.view.width
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
//id: userInfoGrid
|
||||||
|
|
||||||
|
spacing: Nheko.paddingMedium
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Nheko.paddingMedium
|
||||||
|
|
||||||
|
Avatar {
|
||||||
|
//userid: Nheko.currentUser.userid
|
||||||
|
|
||||||
|
id: avatar
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
Layout.preferredWidth: fontMetrics.lineSpacing * 2.5
|
||||||
|
Layout.preferredHeight: fontMetrics.lineSpacing * 2.5
|
||||||
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
displayName: model.roomName
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: textContent
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignLeft
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: 100
|
||||||
|
width: parent.width - avatar.width
|
||||||
|
Layout.preferredWidth: parent.width - avatar.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
ElidedLabel {
|
||||||
|
Layout.alignment: Qt.AlignBottom
|
||||||
|
color: Nheko.colors.text
|
||||||
|
elideWidth: textContent.width - timestamp.width - Nheko.paddingMedium
|
||||||
|
fullText: model.roomName + ": " + model.notificationCount
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: timestamp
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||||
|
font.pixelSize: fontMetrics.font.pixelSize * 0.9
|
||||||
|
color: Nheko.colors.buttonText
|
||||||
|
text: "14:32"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
ElidedLabel {
|
||||||
|
color: Nheko.colors.buttonText
|
||||||
|
font.weight: Font.Thin
|
||||||
|
font.pixelSize: fontMetrics.font.pixelSize * 0.9
|
||||||
|
elideWidth: textContent.width - notificationBubble.width
|
||||||
|
fullText: model.lastMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: notificationBubble
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
height: fontMetrics.font.pixelSize * 1.3
|
||||||
|
width: height
|
||||||
|
radius: height / 2
|
||||||
|
color: Nheko.colors.highlight
|
||||||
|
|
||||||
|
Label {
|
||||||
|
anchors.fill: parent
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
fontSizeMode: Text.Fit
|
||||||
|
color: Nheko.colors.highlightedText
|
||||||
|
text: model.notificationCount
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
height: parent.height - Nheko.paddingSmall * 2
|
||||||
|
width: 3
|
||||||
|
color: Nheko.colors.highlight
|
||||||
|
visible: model.hasUnreadMessages
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: Nheko.theme.sidebarBackground
|
color: Nheko.theme.sidebarBackground
|
||||||
@ -34,8 +160,8 @@ Page {
|
|||||||
id: avatar
|
id: avatar
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.preferredWidth: Nheko.avatarSize
|
Layout.preferredWidth: fontMetrics.lineSpacing * 2
|
||||||
Layout.preferredHeight: Nheko.avatarSize
|
Layout.preferredHeight: fontMetrics.lineSpacing * 2
|
||||||
url: Nheko.currentUser.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: Nheko.currentUser.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: Nheko.currentUser.displayName
|
displayName: Nheko.currentUser.displayName
|
||||||
userid: Nheko.currentUser.userid
|
userid: Nheko.currentUser.userid
|
||||||
@ -46,50 +172,25 @@ Page {
|
|||||||
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.minimumWidth: 100
|
width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
|
||||||
width: parent.width - avatar.width - logoutButton.width
|
Layout.preferredWidth: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
|
||||||
Layout.preferredWidth: parent.width - avatar.width - logoutButton.width
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Label {
|
ElidedLabel {
|
||||||
Layout.alignment: Qt.AlignBottom
|
Layout.alignment: Qt.AlignBottom
|
||||||
color: Nheko.colors.text
|
|
||||||
font.pointSize: fontMetrics.font.pointSize * 1.1
|
font.pointSize: fontMetrics.font.pointSize * 1.1
|
||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
text: userNameText.elidedText
|
fullText: Nheko.currentUser.displayName
|
||||||
maximumLineCount: 1
|
elideWidth: col.width
|
||||||
elide: Text.ElideRight
|
|
||||||
textFormat: Text.PlainText
|
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: userNameText
|
|
||||||
|
|
||||||
font.pointSize: fontMetrics.font.pointSize * 1.1
|
|
||||||
elide: Text.ElideRight
|
|
||||||
elideWidth: col.width
|
|
||||||
text: Nheko.currentUser.displayName
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
ElidedLabel {
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
color: Nheko.colors.buttonText
|
color: Nheko.colors.buttonText
|
||||||
font.weight: Font.Thin
|
font.weight: Font.Thin
|
||||||
text: userIdText.elidedText
|
|
||||||
maximumLineCount: 1
|
|
||||||
textFormat: Text.PlainText
|
|
||||||
font.pointSize: fontMetrics.font.pointSize * 0.9
|
font.pointSize: fontMetrics.font.pointSize * 0.9
|
||||||
|
elideWidth: col.width
|
||||||
TextMetrics {
|
fullText: Nheko.currentUser.userid
|
||||||
id: userIdText
|
|
||||||
|
|
||||||
font.pointSize: fontMetrics.font.pointSize * 0.9
|
|
||||||
elide: Text.ElideRight
|
|
||||||
elideWidth: col.width
|
|
||||||
text: Nheko.currentUser.userid
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@
|
|||||||
<file>qml/Completer.qml</file>
|
<file>qml/Completer.qml</file>
|
||||||
<file>qml/EncryptionIndicator.qml</file>
|
<file>qml/EncryptionIndicator.qml</file>
|
||||||
<file>qml/ImageButton.qml</file>
|
<file>qml/ImageButton.qml</file>
|
||||||
|
<file>qml/ElidedLabel.qml</file>
|
||||||
<file>qml/MatrixText.qml</file>
|
<file>qml/MatrixText.qml</file>
|
||||||
<file>qml/MatrixTextField.qml</file>
|
<file>qml/MatrixTextField.qml</file>
|
||||||
<file>qml/ToggleButton.qml</file>
|
<file>qml/ToggleButton.qml</file>
|
||||||
|
146
src/timeline/RoomlistModel.cpp
Normal file
146
src/timeline/RoomlistModel.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "RoomlistModel.h"
|
||||||
|
|
||||||
|
#include "ChatPage.h"
|
||||||
|
#include "MatrixClient.h"
|
||||||
|
#include "MxcImageProvider.h"
|
||||||
|
#include "TimelineModel.h"
|
||||||
|
#include "TimelineViewManager.h"
|
||||||
|
#include "UserSettingsPage.h"
|
||||||
|
|
||||||
|
RoomlistModel::RoomlistModel(TimelineViewManager *parent)
|
||||||
|
: manager(parent)
|
||||||
|
{
|
||||||
|
connect(ChatPage::instance(), &ChatPage::decryptSidebarChanged, this, [this]() {
|
||||||
|
auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar();
|
||||||
|
QHash<QString, QSharedPointer<TimelineModel>>::iterator i;
|
||||||
|
for (i = models.begin(); i != models.end(); ++i) {
|
||||||
|
auto ptr = i.value();
|
||||||
|
|
||||||
|
if (!ptr.isNull()) {
|
||||||
|
ptr->setDecryptDescription(decrypt);
|
||||||
|
ptr->updateLastMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray>
|
||||||
|
RoomlistModel::roleNames() const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{AvatarUrl, "avatarUrl"},
|
||||||
|
{RoomName, "roomName"},
|
||||||
|
{LastMessage, "lastMessage"},
|
||||||
|
{HasUnreadMessages, "hasUnreadMessages"},
|
||||||
|
{NotificationCount, "notificationCount"},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
RoomlistModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (index.row() >= 0 && static_cast<size_t>(index.row()) < roomids.size()) {
|
||||||
|
auto room = models.value(roomids.at(index.row()));
|
||||||
|
switch (role) {
|
||||||
|
case Roles::AvatarUrl:
|
||||||
|
return room->roomAvatarUrl();
|
||||||
|
case Roles::RoomName:
|
||||||
|
return room->roomName();
|
||||||
|
case Roles::LastMessage:
|
||||||
|
return QString("Nico: Hahaha, this is funny!");
|
||||||
|
case Roles::HasUnreadMessages:
|
||||||
|
return true;
|
||||||
|
case Roles::NotificationCount:
|
||||||
|
return 5;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomlistModel::addRoom(const QString &room_id, bool suppressInsertNotification)
|
||||||
|
{
|
||||||
|
if (!models.contains(room_id)) {
|
||||||
|
QSharedPointer<TimelineModel> newRoom(new TimelineModel(manager, room_id));
|
||||||
|
newRoom->setDecryptDescription(
|
||||||
|
ChatPage::instance()->userSettings()->decryptSidebar());
|
||||||
|
|
||||||
|
connect(newRoom.data(),
|
||||||
|
&TimelineModel::newEncryptedImage,
|
||||||
|
manager->imageProvider(),
|
||||||
|
&MxcImageProvider::addEncryptionInfo);
|
||||||
|
connect(newRoom.data(),
|
||||||
|
&TimelineModel::forwardToRoom,
|
||||||
|
manager,
|
||||||
|
&TimelineViewManager::forwardMessageToRoom);
|
||||||
|
|
||||||
|
if (!suppressInsertNotification)
|
||||||
|
beginInsertRows(QModelIndex(), (int)roomids.size(), (int)roomids.size());
|
||||||
|
models.insert(room_id, std::move(newRoom));
|
||||||
|
roomids.push_back(room_id);
|
||||||
|
if (!suppressInsertNotification)
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomlistModel::sync(const mtx::responses::Rooms &rooms)
|
||||||
|
{
|
||||||
|
for (const auto &[room_id, room] : rooms.join) {
|
||||||
|
// addRoom will only add the room, if it doesn't exist
|
||||||
|
addRoom(QString::fromStdString(room_id));
|
||||||
|
const auto &room_model = models.value(QString::fromStdString(room_id));
|
||||||
|
room_model->syncState(room.state);
|
||||||
|
room_model->addEvents(room.timeline);
|
||||||
|
connect(room_model.data(),
|
||||||
|
&TimelineModel::newCallEvent,
|
||||||
|
manager->callManager(),
|
||||||
|
&CallManager::syncEvent,
|
||||||
|
Qt::UniqueConnection);
|
||||||
|
|
||||||
|
if (ChatPage::instance()->userSettings()->typingNotifications()) {
|
||||||
|
for (const auto &ev : room.ephemeral.events) {
|
||||||
|
if (auto t = std::get_if<
|
||||||
|
mtx::events::EphemeralEvent<mtx::events::ephemeral::Typing>>(
|
||||||
|
&ev)) {
|
||||||
|
std::vector<QString> typing;
|
||||||
|
typing.reserve(t->content.user_ids.size());
|
||||||
|
for (const auto &user : t->content.user_ids) {
|
||||||
|
if (user != http::client()->user_id().to_string())
|
||||||
|
typing.push_back(
|
||||||
|
QString::fromStdString(user));
|
||||||
|
}
|
||||||
|
room_model->updateTypingUsers(typing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomlistModel::initializeRooms(const std::vector<QString> &roomIds_)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
models.clear();
|
||||||
|
roomids.clear();
|
||||||
|
roomids = roomIds_;
|
||||||
|
for (const auto &id : roomIds_)
|
||||||
|
addRoom(id, true);
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomlistModel::clear()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
models.clear();
|
||||||
|
roomids.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
58
src/timeline/RoomlistModel.h
Normal file
58
src/timeline/RoomlistModel.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <mtx/responses/sync.hpp>
|
||||||
|
|
||||||
|
class TimelineModel;
|
||||||
|
class TimelineViewManager;
|
||||||
|
|
||||||
|
class RoomlistModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum Roles
|
||||||
|
{
|
||||||
|
AvatarUrl = Qt::UserRole,
|
||||||
|
RoomName,
|
||||||
|
LastMessage,
|
||||||
|
HasUnreadMessages,
|
||||||
|
NotificationCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
RoomlistModel(TimelineViewManager *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;
|
||||||
|
QSharedPointer<TimelineModel> getRoomById(QString id) const
|
||||||
|
{
|
||||||
|
if (models.contains(id))
|
||||||
|
return models.value(id);
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void initializeRooms(const std::vector<QString> &roomids);
|
||||||
|
void sync(const mtx::responses::Rooms &rooms);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
|
||||||
|
|
||||||
|
TimelineViewManager *manager = nullptr;
|
||||||
|
std::vector<QString> roomids;
|
||||||
|
QHash<QString, QSharedPointer<TimelineModel>> models;
|
||||||
|
};
|
||||||
|
|
@ -86,21 +86,6 @@ removeReplyFallback(mtx::events::Event<T> &e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::updateEncryptedDescriptions()
|
|
||||||
{
|
|
||||||
auto decrypt = ChatPage::instance()->userSettings()->decryptSidebar();
|
|
||||||
QHash<QString, QSharedPointer<TimelineModel>>::iterator i;
|
|
||||||
for (i = models.begin(); i != models.end(); ++i) {
|
|
||||||
auto ptr = i.value();
|
|
||||||
|
|
||||||
if (!ptr.isNull()) {
|
|
||||||
ptr->setDecryptDescription(decrypt);
|
|
||||||
ptr->updateLastMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::updateColorPalette()
|
TimelineViewManager::updateColorPalette()
|
||||||
{
|
{
|
||||||
@ -148,6 +133,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||||||
, colorImgProvider(new ColorImageProvider())
|
, colorImgProvider(new ColorImageProvider())
|
||||||
, blurhashProvider(new BlurhashProvider())
|
, blurhashProvider(new BlurhashProvider())
|
||||||
, callManager_(callManager)
|
, callManager_(callManager)
|
||||||
|
, rooms(new RoomlistModel(this))
|
||||||
{
|
{
|
||||||
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
|
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
|
||||||
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
|
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
|
||||||
@ -205,6 +191,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||||||
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||||
return ptr;
|
return ptr;
|
||||||
});
|
});
|
||||||
|
qmlRegisterSingletonType<RoomlistModel>(
|
||||||
|
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||||
|
auto ptr = self->rooms;
|
||||||
|
QQmlEngine::setObjectOwnership(ptr, QQmlEngine::CppOwnership);
|
||||||
|
return ptr;
|
||||||
|
});
|
||||||
qmlRegisterSingletonType<UserSettings>(
|
qmlRegisterSingletonType<UserSettings>(
|
||||||
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||||
auto ptr = ChatPage::instance()->userSettings().data();
|
auto ptr = ChatPage::instance()->userSettings().data();
|
||||||
@ -260,10 +252,6 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||||||
view->setSource(QUrl("qrc:///qml/Root.qml"));
|
view->setSource(QUrl("qrc:///qml/Root.qml"));
|
||||||
|
|
||||||
connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
|
connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
|
||||||
connect(parent,
|
|
||||||
&ChatPage::decryptSidebarChanged,
|
|
||||||
this,
|
|
||||||
&TimelineViewManager::updateEncryptedDescriptions);
|
|
||||||
connect(
|
connect(
|
||||||
dynamic_cast<ChatPage *>(parent),
|
dynamic_cast<ChatPage *>(parent),
|
||||||
&ChatPage::receivedRoomDeviceVerificationRequest,
|
&ChatPage::receivedRoomDeviceVerificationRequest,
|
||||||
@ -334,64 +322,13 @@ TimelineViewManager::setVideoCallItem()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
|
TimelineViewManager::sync(const mtx::responses::Rooms &rooms_)
|
||||||
{
|
{
|
||||||
for (const auto &[room_id, room] : rooms.join) {
|
this->rooms->sync(rooms_);
|
||||||
// addRoom will only add the room, if it doesn't exist
|
|
||||||
addRoom(QString::fromStdString(room_id));
|
|
||||||
const auto &room_model = models.value(QString::fromStdString(room_id));
|
|
||||||
if (!isInitialSync_)
|
|
||||||
connect(room_model.data(),
|
|
||||||
&TimelineModel::newCallEvent,
|
|
||||||
callManager_,
|
|
||||||
&CallManager::syncEvent);
|
|
||||||
room_model->syncState(room.state);
|
|
||||||
room_model->addEvents(room.timeline);
|
|
||||||
if (!isInitialSync_)
|
|
||||||
disconnect(room_model.data(),
|
|
||||||
&TimelineModel::newCallEvent,
|
|
||||||
callManager_,
|
|
||||||
&CallManager::syncEvent);
|
|
||||||
|
|
||||||
if (ChatPage::instance()->userSettings()->typingNotifications()) {
|
if (isInitialSync_) {
|
||||||
for (const auto &ev : room.ephemeral.events) {
|
this->isInitialSync_ = false;
|
||||||
if (auto t = std::get_if<
|
emit initialSyncChanged(false);
|
||||||
mtx::events::EphemeralEvent<mtx::events::ephemeral::Typing>>(
|
|
||||||
&ev)) {
|
|
||||||
std::vector<QString> typing;
|
|
||||||
typing.reserve(t->content.user_ids.size());
|
|
||||||
for (const auto &user : t->content.user_ids) {
|
|
||||||
if (user != http::client()->user_id().to_string())
|
|
||||||
typing.push_back(
|
|
||||||
QString::fromStdString(user));
|
|
||||||
}
|
|
||||||
room_model->updateTypingUsers(typing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->isInitialSync_ = false;
|
|
||||||
emit initialSyncChanged(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::addRoom(const QString &room_id)
|
|
||||||
{
|
|
||||||
if (!models.contains(room_id)) {
|
|
||||||
QSharedPointer<TimelineModel> newRoom(new TimelineModel(this, room_id));
|
|
||||||
newRoom->setDecryptDescription(
|
|
||||||
ChatPage::instance()->userSettings()->decryptSidebar());
|
|
||||||
|
|
||||||
connect(newRoom.data(),
|
|
||||||
&TimelineModel::newEncryptedImage,
|
|
||||||
imgProvider,
|
|
||||||
&MxcImageProvider::addEncryptionInfo);
|
|
||||||
connect(newRoom.data(),
|
|
||||||
&TimelineModel::forwardToRoom,
|
|
||||||
this,
|
|
||||||
&TimelineViewManager::forwardMessageToRoom);
|
|
||||||
models.insert(room_id, std::move(newRoom));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,9 +337,8 @@ TimelineViewManager::setHistoryView(const QString &room_id)
|
|||||||
{
|
{
|
||||||
nhlog::ui()->info("Trying to activate room {}", room_id.toStdString());
|
nhlog::ui()->info("Trying to activate room {}", room_id.toStdString());
|
||||||
|
|
||||||
auto room = models.find(room_id);
|
if (auto room = rooms->getRoomById(room_id)) {
|
||||||
if (room != models.end()) {
|
timeline_ = room.get();
|
||||||
timeline_ = room.value().data();
|
|
||||||
emit activeTimelineChanged(timeline_);
|
emit activeTimelineChanged(timeline_);
|
||||||
container->setFocus();
|
container->setFocus();
|
||||||
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
||||||
@ -418,10 +354,9 @@ TimelineViewManager::highlightRoom(const QString &room_id)
|
|||||||
void
|
void
|
||||||
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
|
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
|
||||||
{
|
{
|
||||||
auto room = models.find(room_id);
|
if (auto room = rooms->getRoomById(room_id)) {
|
||||||
if (room != models.end()) {
|
if (timeline_ != room) {
|
||||||
if (timeline_ != room.value().data()) {
|
timeline_ = room.get();
|
||||||
timeline_ = room.value().data();
|
|
||||||
emit activeTimelineChanged(timeline_);
|
emit activeTimelineChanged(timeline_);
|
||||||
container->setFocus();
|
container->setFocus();
|
||||||
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
||||||
@ -505,17 +440,21 @@ TimelineViewManager::verifyUser(QString userid)
|
|||||||
if (std::find(room_members.begin(),
|
if (std::find(room_members.begin(),
|
||||||
room_members.end(),
|
room_members.end(),
|
||||||
(userid).toStdString()) != room_members.end()) {
|
(userid).toStdString()) != room_members.end()) {
|
||||||
auto model = models.value(QString::fromStdString(room_id));
|
if (auto model =
|
||||||
auto flow = DeviceVerificationFlow::InitiateUserVerification(
|
rooms->getRoomById(QString::fromStdString(room_id))) {
|
||||||
this, model.data(), userid);
|
auto flow =
|
||||||
connect(model.data(),
|
DeviceVerificationFlow::InitiateUserVerification(
|
||||||
&TimelineModel::updateFlowEventId,
|
this, model.data(), userid);
|
||||||
this,
|
connect(model.data(),
|
||||||
[this, flow](std::string eventId) {
|
&TimelineModel::updateFlowEventId,
|
||||||
dvList[QString::fromStdString(eventId)] = flow;
|
this,
|
||||||
});
|
[this, flow](std::string eventId) {
|
||||||
emit newDeviceVerificationRequest(flow.data());
|
dvList[QString::fromStdString(eventId)] =
|
||||||
return;
|
flow;
|
||||||
|
});
|
||||||
|
emit newDeviceVerificationRequest(flow.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,26 +487,23 @@ void
|
|||||||
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
||||||
const std::vector<QString> &event_ids)
|
const std::vector<QString> &event_ids)
|
||||||
{
|
{
|
||||||
auto room = models.find(room_id);
|
if (auto room = rooms->getRoomById(room_id)) {
|
||||||
if (room != models.end()) {
|
room->markEventsAsRead(event_ids);
|
||||||
room.value()->markEventsAsRead(event_ids);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::string &session_id)
|
TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::string &session_id)
|
||||||
{
|
{
|
||||||
auto room = models.find(QString::fromStdString(room_id));
|
if (auto room = rooms->getRoomById(QString::fromStdString(room_id))) {
|
||||||
if (room != models.end()) {
|
room->receivedSessionKey(session_id);
|
||||||
room.value()->receivedSessionKey(session_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
|
TimelineViewManager::initWithMessages(const std::vector<QString> &roomIds)
|
||||||
{
|
{
|
||||||
for (const auto &roomId : roomIds)
|
rooms->initializeRooms(roomIds);
|
||||||
addRoom(roomId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -575,10 +511,9 @@ TimelineViewManager::queueReply(const QString &roomid,
|
|||||||
const QString &repliedToEvent,
|
const QString &repliedToEvent,
|
||||||
const QString &replyBody)
|
const QString &replyBody)
|
||||||
{
|
{
|
||||||
auto room = models.find(roomid);
|
if (auto room = rooms->getRoomById(roomid)) {
|
||||||
if (room != models.end()) {
|
room->setReply(repliedToEvent);
|
||||||
room.value()->setReply(repliedToEvent);
|
room->input()->message(replyBody);
|
||||||
room.value()->input()->message(replyBody);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,29 +555,32 @@ void
|
|||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallInvite &callInvite)
|
const mtx::events::msg::CallInvite &callInvite)
|
||||||
{
|
{
|
||||||
models.value(roomid)->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
|
if (auto room = rooms->getRoomById(roomid))
|
||||||
|
room->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallCandidates &callCandidates)
|
const mtx::events::msg::CallCandidates &callCandidates)
|
||||||
{
|
{
|
||||||
models.value(roomid)->sendMessageEvent(callCandidates,
|
if (auto room = rooms->getRoomById(roomid))
|
||||||
mtx::events::EventType::CallCandidates);
|
room->sendMessageEvent(callCandidates, mtx::events::EventType::CallCandidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallAnswer &callAnswer)
|
const mtx::events::msg::CallAnswer &callAnswer)
|
||||||
{
|
{
|
||||||
models.value(roomid)->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
|
if (auto room = rooms->getRoomById(roomid))
|
||||||
|
room->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallHangUp &callHangUp)
|
const mtx::events::msg::CallHangUp &callHangUp)
|
||||||
{
|
{
|
||||||
models.value(roomid)->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
if (auto room = rooms->getRoomById(roomid))
|
||||||
|
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -693,7 +631,7 @@ void
|
|||||||
TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents *e,
|
TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents *e,
|
||||||
QString roomId)
|
QString roomId)
|
||||||
{
|
{
|
||||||
auto room = models.find(roomId);
|
auto room = rooms->getRoomById(roomId);
|
||||||
auto content = mtx::accessors::url(*e);
|
auto content = mtx::accessors::url(*e);
|
||||||
std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
|
std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
|
||||||
|
|
||||||
@ -736,12 +674,15 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven
|
|||||||
ev.content.url = url;
|
ev.content.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto room = models.find(roomId);
|
if (auto room = rooms->getRoomById(roomId)) {
|
||||||
removeReplyFallback(ev);
|
removeReplyFallback(ev);
|
||||||
ev.content.relations.relations.clear();
|
ev.content.relations.relations
|
||||||
room.value()->sendMessageEvent(
|
.clear();
|
||||||
ev.content,
|
room->sendMessageEvent(
|
||||||
mtx::events::EventType::RoomMessage);
|
ev.content,
|
||||||
|
mtx::events::EventType::
|
||||||
|
RoomMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*e);
|
*e);
|
||||||
@ -759,8 +700,7 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven
|
|||||||
mtx::events::EventType::RoomMessage) {
|
mtx::events::EventType::RoomMessage) {
|
||||||
e.content.relations.relations.clear();
|
e.content.relations.relations.clear();
|
||||||
removeReplyFallback(e);
|
removeReplyFallback(e);
|
||||||
room.value()->sendMessageEvent(e.content,
|
room->sendMessageEvent(e.content, mtx::events::EventType::RoomMessage);
|
||||||
mtx::events::EventType::RoomMessage);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*e);
|
*e);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "WebRTCSession.h"
|
#include "WebRTCSession.h"
|
||||||
#include "emoji/EmojiModel.h"
|
#include "emoji/EmojiModel.h"
|
||||||
#include "emoji/Provider.h"
|
#include "emoji/Provider.h"
|
||||||
|
#include "timeline/RoomlistModel.h"
|
||||||
|
|
||||||
class MxcImageProvider;
|
class MxcImageProvider;
|
||||||
class BlurhashProvider;
|
class BlurhashProvider;
|
||||||
@ -48,13 +49,15 @@ public:
|
|||||||
QWidget *getWidget() const { return container; }
|
QWidget *getWidget() const { return container; }
|
||||||
|
|
||||||
void sync(const mtx::responses::Rooms &rooms);
|
void sync(const mtx::responses::Rooms &rooms);
|
||||||
void addRoom(const QString &room_id);
|
|
||||||
|
MxcImageProvider *imageProvider() { return imgProvider; }
|
||||||
|
CallManager *callManager() { return callManager_; }
|
||||||
|
|
||||||
void clearAll()
|
void clearAll()
|
||||||
{
|
{
|
||||||
timeline_ = nullptr;
|
timeline_ = nullptr;
|
||||||
emit activeTimelineChanged(nullptr);
|
emit activeTimelineChanged(nullptr);
|
||||||
models.clear();
|
rooms->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
|
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
|
||||||
@ -109,11 +112,7 @@ public slots:
|
|||||||
void focusTimeline();
|
void focusTimeline();
|
||||||
TimelineModel *getHistoryView(const QString &room_id)
|
TimelineModel *getHistoryView(const QString &room_id)
|
||||||
{
|
{
|
||||||
auto room = models.find(room_id);
|
return rooms->getRoomById(room_id).get();
|
||||||
if (room != models.end())
|
|
||||||
return room.value().data();
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateColorPalette();
|
void updateColorPalette();
|
||||||
@ -126,7 +125,6 @@ public slots:
|
|||||||
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallAnswer &);
|
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallAnswer &);
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallHangUp &);
|
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallHangUp &);
|
||||||
|
|
||||||
void updateEncryptedDescriptions();
|
|
||||||
void setVideoCallItem();
|
void setVideoCallItem();
|
||||||
|
|
||||||
void enableBackButton()
|
void enableBackButton()
|
||||||
@ -163,7 +161,6 @@ private:
|
|||||||
ColorImageProvider *colorImgProvider;
|
ColorImageProvider *colorImgProvider;
|
||||||
BlurhashProvider *blurhashProvider;
|
BlurhashProvider *blurhashProvider;
|
||||||
|
|
||||||
QHash<QString, QSharedPointer<TimelineModel>> models;
|
|
||||||
TimelineModel *timeline_ = nullptr;
|
TimelineModel *timeline_ = nullptr;
|
||||||
CallManager *callManager_ = nullptr;
|
CallManager *callManager_ = nullptr;
|
||||||
|
|
||||||
@ -171,6 +168,8 @@ private:
|
|||||||
bool isNarrowView_ = false;
|
bool isNarrowView_ = false;
|
||||||
bool isWindowFocused_ = false;
|
bool isWindowFocused_ = false;
|
||||||
|
|
||||||
|
RoomlistModel *rooms = nullptr;
|
||||||
|
|
||||||
QHash<QString, QColor> userColors;
|
QHash<QString, QColor> userColors;
|
||||||
|
|
||||||
QHash<QString, QSharedPointer<DeviceVerificationFlow>> dvList;
|
QHash<QString, QSharedPointer<DeviceVerificationFlow>> dvList;
|
||||||
|
Loading…
Reference in New Issue
Block a user