mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
Port top bar to Qml
Also fixes some resize issues with stupid workarounds to our resize logic. This really needs to be cleaned up at some point!
This commit is contained in:
parent
c4e4938d35
commit
640b0ee405
12 changed files with 267 additions and 448 deletions
|
@ -304,7 +304,6 @@ set(SRC_FILES
|
|||
src/SideBarActions.cpp
|
||||
src/Splitter.cpp
|
||||
src/TextInputWidget.cpp
|
||||
src/TopRoomBar.cpp
|
||||
src/TrayIcon.cpp
|
||||
src/UserInfoWidget.cpp
|
||||
src/UserSettingsPage.cpp
|
||||
|
@ -512,7 +511,6 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||
src/SideBarActions.h
|
||||
src/Splitter.h
|
||||
src/TextInputWidget.h
|
||||
src/TopRoomBar.h
|
||||
src/TrayIcon.h
|
||||
src/UserInfoWidget.h
|
||||
src/UserSettingsPage.h
|
||||
|
|
|
@ -50,6 +50,8 @@ Rectangle {
|
|||
anchors.bottom: avatar.bottom
|
||||
anchors.right: avatar.right
|
||||
|
||||
visible: !!userid
|
||||
|
||||
height: avatar.height / 6
|
||||
width: height
|
||||
radius: settings.avatarCircles ? height / 2 : height / 4
|
||||
|
|
|
@ -115,6 +115,112 @@ Page {
|
|||
z: 3
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
id: topBar
|
||||
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: topLayout.height + 16
|
||||
z: 3
|
||||
|
||||
color: colors.base
|
||||
|
||||
GridLayout {
|
||||
id: topLayout
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
//Layout.margins: 8
|
||||
|
||||
ImageButton {
|
||||
id: backToRoomsButton
|
||||
|
||||
Layout.column: 0
|
||||
Layout.row: 0
|
||||
Layout.rowSpan: 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
visible: timelineManager.isNarrowView
|
||||
|
||||
image: ":/icons/icons/ui/angle-pointing-to-left.png"
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Back to room list")
|
||||
|
||||
onClicked: timelineManager.backToRooms()
|
||||
}
|
||||
|
||||
Avatar {
|
||||
Layout.column: 1
|
||||
Layout.row: 0
|
||||
Layout.rowSpan: 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
width: avatarSize
|
||||
height: avatarSize
|
||||
url: chat.model.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||
displayName: chat.model.roomName
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.column: 2
|
||||
Layout.row: 0
|
||||
|
||||
font.pointSize: fontMetrics.font.pointSize * 1.1
|
||||
text: chat.model.roomName
|
||||
}
|
||||
MatrixText {
|
||||
Layout.fillWidth: true
|
||||
Layout.column: 2
|
||||
Layout.row: 1
|
||||
text: chat.model.roomTopic
|
||||
Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines
|
||||
clip: true
|
||||
}
|
||||
|
||||
ImageButton {
|
||||
id: roomOptionsButton
|
||||
|
||||
Layout.column: 3
|
||||
Layout.row: 0
|
||||
Layout.rowSpan: 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
image: ":/icons/icons/ui/vertical-ellipsis.png"
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Room options")
|
||||
|
||||
onClicked: roomOptionsMenu.popup(roomOptionsButton)
|
||||
|
||||
Menu {
|
||||
id: roomOptionsMenu
|
||||
MenuItem {
|
||||
text: qsTr("Invite users")
|
||||
onTriggered: timelineManager.openInviteUsersDialog();
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("Members")
|
||||
onTriggered: timelineManager.openMemberListDialog();
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("Leave room")
|
||||
onTriggered: timelineManager.openLeaveRoomDialog();
|
||||
}
|
||||
MenuItem {
|
||||
text: qsTr("Settings")
|
||||
onTriggered: timelineManager.openRoomSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: chat
|
||||
|
||||
|
@ -122,13 +228,8 @@ Page {
|
|||
|
||||
cacheBuffer: 400
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: chatFooter.top
|
||||
width: parent.width
|
||||
|
||||
anchors.leftMargin: 4
|
||||
anchors.rightMargin: scrollbar.width
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: timelineManager.timeline
|
||||
|
||||
|
@ -167,10 +268,6 @@ Page {
|
|||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollbar
|
||||
parent: chat.parent
|
||||
anchors.top: chat.top
|
||||
anchors.right: chat.right
|
||||
anchors.bottom: chat.bottom
|
||||
}
|
||||
|
||||
spacing: 4
|
||||
|
@ -178,9 +275,9 @@ Page {
|
|||
|
||||
onCountChanged: if (atYEnd) model.currentIndex = 0 // Mark last event as read, since we are at the bottom
|
||||
|
||||
property int delegateMaxWidth: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > 32) ? settings.timelineMaxWidth : (parent.width - 32)
|
||||
property int delegateMaxWidth: (settings.timelineMaxWidth > 100 && (parent.width - settings.timelineMaxWidth) > scrollbar.width*2) ? settings.timelineMaxWidth : (parent.width - scrollbar.width*2)
|
||||
|
||||
delegate: Rectangle {
|
||||
delegate: Item {
|
||||
// This would normally be previousSection, but our model's order is inverted.
|
||||
property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1
|
||||
|
||||
|
@ -189,7 +286,6 @@ Page {
|
|||
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
|
||||
width: chat.delegateMaxWidth
|
||||
height: section ? section.height + timelinerow.height : timelinerow.height
|
||||
color: "transparent"
|
||||
|
||||
TimelineRow {
|
||||
id: timelinerow
|
||||
|
@ -309,17 +405,13 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: chatFooter
|
||||
|
||||
height: Math.max(fontMetrics.height * 1.2, footerContent.height)
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
implicitHeight: Math.max(fontMetrics.height * 1.2, footerContent.height)
|
||||
Layout.fillWidth: true
|
||||
z: 3
|
||||
|
||||
color: "transparent"
|
||||
|
||||
Column {
|
||||
id: footerContent
|
||||
anchors.left: parent.left
|
||||
|
@ -382,4 +474,5 @@ Page {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
105
src/ChatPage.cpp
105
src/ChatPage.cpp
|
@ -37,7 +37,6 @@
|
|||
#include "SideBarActions.h"
|
||||
#include "Splitter.h"
|
||||
#include "TextInputWidget.h"
|
||||
#include "TopRoomBar.h"
|
||||
#include "UserInfoWidget.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "Utils.h"
|
||||
|
@ -126,10 +125,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
contentLayout_->setSpacing(0);
|
||||
contentLayout_->setMargin(0);
|
||||
|
||||
top_bar_ = new TopRoomBar(this);
|
||||
view_manager_ = new TimelineViewManager(userSettings_, &callManager_, this);
|
||||
|
||||
contentLayout_->addWidget(top_bar_);
|
||||
contentLayout_->addWidget(view_manager_->getWidget());
|
||||
|
||||
activeCallBar_ = new ActiveCallBar(this);
|
||||
|
@ -181,30 +178,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
room_list_->previousRoom();
|
||||
});
|
||||
|
||||
connect(top_bar_, &TopRoomBar::mentionsClicked, this, [this](const QPoint &mentionsPos) {
|
||||
if (user_mentions_popup_->isVisible()) {
|
||||
user_mentions_popup_->hide();
|
||||
} else {
|
||||
showNotificationsDialog(mentionsPos);
|
||||
http::client()->notifications(
|
||||
1000,
|
||||
"",
|
||||
"highlight",
|
||||
[this, mentionsPos](const mtx::responses::Notifications &res,
|
||||
mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
nhlog::net()->warn(
|
||||
"failed to retrieve notifications: {} ({})",
|
||||
err->matrix_error.error,
|
||||
static_cast<int>(err->status_code));
|
||||
return;
|
||||
}
|
||||
|
||||
emit highlightedNotifsRetrieved(std::move(res), mentionsPos);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
connectivityTimer_.setInterval(CHECK_CONNECTIVITY_INTERVAL);
|
||||
connect(&connectivityTimer_, &QTimer::timeout, this, [=]() {
|
||||
if (http::client()->access_token().empty()) {
|
||||
|
@ -226,8 +199,9 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
|
||||
connect(this, &ChatPage::loggedOut, this, &ChatPage::logout);
|
||||
|
||||
connect(top_bar_, &TopRoomBar::showRoomList, splitter, &Splitter::showFullRoomList);
|
||||
connect(top_bar_, &TopRoomBar::inviteUsers, this, [this](QStringList users) {
|
||||
connect(
|
||||
view_manager_, &TimelineViewManager::showRoomList, splitter, &Splitter::showFullRoomList);
|
||||
connect(view_manager_, &TimelineViewManager::inviteUsers, this, [this](QStringList users) {
|
||||
const auto room_id = current_room_.toStdString();
|
||||
|
||||
for (int ii = 0; ii < users.size(); ++ii) {
|
||||
|
@ -252,7 +226,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
});
|
||||
|
||||
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::stopTyping);
|
||||
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
|
||||
connect(room_list_, &RoomList::roomChanged, splitter, &Splitter::showChatView);
|
||||
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit);
|
||||
connect(
|
||||
|
@ -487,8 +460,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
}
|
||||
});
|
||||
|
||||
connect(room_list_, &RoomList::roomAvatarChanged, this, &ChatPage::updateTopBarAvatar);
|
||||
|
||||
connect(
|
||||
this, &ChatPage::updateGroupsInfo, communitiesList_, &CommunitiesList::setCommunities);
|
||||
|
||||
|
@ -588,11 +559,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
|||
});
|
||||
connect(this, &ChatPage::syncRoomlist, room_list_, &RoomList::sync);
|
||||
connect(this, &ChatPage::syncTags, communitiesList_, &CommunitiesList::syncTags);
|
||||
connect(
|
||||
this, &ChatPage::syncTopBar, this, [this](const std::map<QString, RoomInfo> &updates) {
|
||||
if (updates.find(currentRoom()) != updates.end())
|
||||
changeTopRoomInfo(currentRoom());
|
||||
});
|
||||
|
||||
// Callbacks to update the user info (top left corner of the page).
|
||||
connect(this, &ChatPage::setUserAvatar, user_info_widget_, &UserInfoWidget::setAvatar);
|
||||
|
@ -657,7 +623,6 @@ void
|
|||
ChatPage::resetUI()
|
||||
{
|
||||
room_list_->clear();
|
||||
top_bar_->reset();
|
||||
user_info_widget_->reset();
|
||||
view_manager_->clearAll();
|
||||
|
||||
|
@ -786,46 +751,6 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
|||
tryInitialSync();
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::updateTopBarAvatar(const QString &roomid, const QString &img)
|
||||
{
|
||||
if (current_room_ != roomid)
|
||||
return;
|
||||
|
||||
top_bar_->updateRoomAvatar(img);
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::changeTopRoomInfo(const QString &room_id)
|
||||
{
|
||||
if (room_id.isEmpty()) {
|
||||
nhlog::ui()->warn("cannot switch to empty room_id");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto room_info = cache::getRoomInfo({room_id.toStdString()});
|
||||
|
||||
if (room_info.find(room_id) == room_info.end())
|
||||
return;
|
||||
|
||||
const auto name = QString::fromStdString(room_info[room_id].name);
|
||||
const auto avatar_url = QString::fromStdString(room_info[room_id].avatar_url);
|
||||
|
||||
top_bar_->updateRoomName(name);
|
||||
top_bar_->updateRoomTopic(QString::fromStdString(room_info[room_id].topic));
|
||||
|
||||
top_bar_->updateRoomAvatarFromName(name);
|
||||
if (!avatar_url.isEmpty())
|
||||
top_bar_->updateRoomAvatar(avatar_url);
|
||||
|
||||
} catch (const lmdb::error &e) {
|
||||
nhlog::ui()->error("failed to change top bar room info: {}", e.what());
|
||||
}
|
||||
|
||||
current_room_ = room_id;
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::showUnreadMessageNotification(int count)
|
||||
{
|
||||
|
@ -1070,7 +995,6 @@ ChatPage::handleSyncResponse(mtx::responses::Sync res)
|
|||
|
||||
auto updates = cache::roomUpdates(res);
|
||||
|
||||
emit syncTopBar(updates);
|
||||
emit syncRoomlist(updates);
|
||||
|
||||
emit syncUI(res.rooms);
|
||||
|
@ -1481,9 +1405,12 @@ ChatPage::getProfileInfo()
|
|||
void
|
||||
ChatPage::hideSideBars()
|
||||
{
|
||||
communitiesList_->hide();
|
||||
sideBar_->hide();
|
||||
top_bar_->enableBackButton();
|
||||
// Don't hide side bar, if we are currently only showing the side bar!
|
||||
if (view_manager_->getWidget()->isVisible()) {
|
||||
communitiesList_->hide();
|
||||
sideBar_->hide();
|
||||
}
|
||||
view_manager_->enableBackButton();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1493,23 +1420,19 @@ ChatPage::showSideBars()
|
|||
communitiesList_->show();
|
||||
|
||||
sideBar_->show();
|
||||
top_bar_->disableBackButton();
|
||||
view_manager_->disableBackButton();
|
||||
content_->show();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ChatPage::timelineWidth()
|
||||
{
|
||||
int sidebarWidth = sideBar_->size().width();
|
||||
sidebarWidth += communitiesList_->size().width();
|
||||
int sidebarWidth = sideBar_->minimumSize().width();
|
||||
sidebarWidth += communitiesList_->minimumSize().width();
|
||||
nhlog::ui()->info("timelineWidth: {}", size().width() - sidebarWidth);
|
||||
|
||||
return size().width() - sidebarWidth;
|
||||
}
|
||||
bool
|
||||
ChatPage::isSideBarExpanded()
|
||||
{
|
||||
const auto sz = splitter::calculateSidebarSizes(QFont{});
|
||||
return sideBar_->size().width() > sz.normal;
|
||||
}
|
||||
|
||||
void
|
||||
ChatPage::initiateLogout()
|
||||
|
|
|
@ -49,7 +49,6 @@ class SideBarActions;
|
|||
class Splitter;
|
||||
class TextInputWidget;
|
||||
class TimelineViewManager;
|
||||
class TopRoomBar;
|
||||
class UserInfoWidget;
|
||||
class UserSettings;
|
||||
|
||||
|
@ -82,7 +81,6 @@ public:
|
|||
|
||||
//! Calculate the width of the message timeline.
|
||||
uint64_t timelineWidth();
|
||||
bool isSideBarExpanded();
|
||||
//! Hide the room & group list (if it was visible).
|
||||
void hideSideBars();
|
||||
//! Show the room/group list (if it was visible).
|
||||
|
@ -150,7 +148,6 @@ signals:
|
|||
void syncUI(const mtx::responses::Rooms &rooms);
|
||||
void syncRoomlist(const std::map<QString, RoomInfo> &updates);
|
||||
void syncTags(const std::map<QString, RoomInfo> &updates);
|
||||
void syncTopBar(const std::map<QString, RoomInfo> &updates);
|
||||
void dropToLoginPageCb(const QString &msg);
|
||||
|
||||
void notifyMessage(const QString &roomid,
|
||||
|
@ -167,8 +164,6 @@ signals:
|
|||
|
||||
private slots:
|
||||
void showUnreadMessageNotification(int count);
|
||||
void updateTopBarAvatar(const QString &roomid, const QString &img);
|
||||
void changeTopRoomInfo(const QString &room_id);
|
||||
void logout();
|
||||
void removeRoom(const QString &room_id);
|
||||
void dropToLoginPage(const QString &msg);
|
||||
|
@ -239,7 +234,6 @@ private:
|
|||
TimelineViewManager *view_manager_;
|
||||
SideBarActions *sidebarActions_;
|
||||
|
||||
TopRoomBar *top_bar_;
|
||||
TextInputWidget *text_input_;
|
||||
ActiveCallBar *activeCallBar_;
|
||||
|
||||
|
|
|
@ -200,7 +200,8 @@ MainWindow::adjustSideBars()
|
|||
const uint64_t timelineWidth = chat_page_->timelineWidth();
|
||||
const uint64_t minAvailableWidth = sz.collapsePoint + sz.groups;
|
||||
|
||||
if (timelineWidth < minAvailableWidth && !chat_page_->isSideBarExpanded()) {
|
||||
nhlog::ui()->info("timelineWidth: {}, min {}", timelineWidth, minAvailableWidth);
|
||||
if (timelineWidth < minAvailableWidth) {
|
||||
chat_page_->hideSideBars();
|
||||
} else {
|
||||
chat_page_->showSideBars();
|
||||
|
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QAction>
|
||||
#include <QIcon>
|
||||
#include <QLabel>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QPoint>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Config.h"
|
||||
#include "MainWindow.h"
|
||||
#include "TopRoomBar.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Avatar.h"
|
||||
#include "ui/FlatButton.h"
|
||||
#include "ui/Menu.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
#include "ui/TextLabel.h"
|
||||
|
||||
TopRoomBar::TopRoomBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, buttonSize_{32}
|
||||
{
|
||||
QFont f;
|
||||
f.setPointSizeF(f.pointSizeF());
|
||||
|
||||
const int fontHeight = QFontMetrics(f).height();
|
||||
const int widgetMargin = fontHeight / 3;
|
||||
const int contentHeight = fontHeight * 3;
|
||||
|
||||
setFixedHeight(contentHeight + widgetMargin);
|
||||
|
||||
topLayout_ = new QHBoxLayout(this);
|
||||
topLayout_->setSpacing(widgetMargin);
|
||||
topLayout_->setContentsMargins(
|
||||
2 * widgetMargin, widgetMargin, 2 * widgetMargin, widgetMargin);
|
||||
|
||||
avatar_ = new Avatar(this, fontHeight * 2);
|
||||
avatar_->setLetter("");
|
||||
|
||||
textLayout_ = new QVBoxLayout();
|
||||
textLayout_->setSpacing(0);
|
||||
textLayout_->setMargin(0);
|
||||
|
||||
QFont roomFont;
|
||||
roomFont.setPointSizeF(roomFont.pointSizeF() * 1.1);
|
||||
roomFont.setWeight(QFont::Medium);
|
||||
|
||||
nameLabel_ = new QLabel(this);
|
||||
nameLabel_->setFont(roomFont);
|
||||
nameLabel_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
||||
|
||||
QFont descriptionFont;
|
||||
|
||||
topicLabel_ = new TextLabel(this);
|
||||
topicLabel_->setLineWrapMode(QTextEdit::NoWrap);
|
||||
topicLabel_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
topicLabel_->setFont(descriptionFont);
|
||||
topicLabel_->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
topicLabel_->setOpenExternalLinks(true);
|
||||
topicLabel_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
||||
|
||||
textLayout_->addWidget(nameLabel_);
|
||||
textLayout_->addWidget(topicLabel_);
|
||||
|
||||
settingsBtn_ = new FlatButton(this);
|
||||
settingsBtn_->setToolTip(tr("Room options"));
|
||||
settingsBtn_->setFixedSize(buttonSize_, buttonSize_);
|
||||
settingsBtn_->setCornerRadius(buttonSize_ / 2);
|
||||
|
||||
mentionsBtn_ = new FlatButton(this);
|
||||
mentionsBtn_->setToolTip(tr("Mentions"));
|
||||
mentionsBtn_->setFixedSize(buttonSize_, buttonSize_);
|
||||
mentionsBtn_->setCornerRadius(buttonSize_ / 2);
|
||||
|
||||
QIcon settings_icon;
|
||||
settings_icon.addFile(":/icons/icons/ui/vertical-ellipsis.png");
|
||||
settingsBtn_->setIcon(settings_icon);
|
||||
settingsBtn_->setIconSize(QSize(buttonSize_ / 2, buttonSize_ / 2));
|
||||
|
||||
QIcon mentions_icon;
|
||||
mentions_icon.addFile(":/icons/icons/ui/at-solid.svg");
|
||||
mentionsBtn_->setIcon(mentions_icon);
|
||||
mentionsBtn_->setIconSize(QSize(buttonSize_ / 2, buttonSize_ / 2));
|
||||
|
||||
backBtn_ = new FlatButton(this);
|
||||
backBtn_->setFixedSize(buttonSize_, buttonSize_);
|
||||
backBtn_->setCornerRadius(buttonSize_ / 2);
|
||||
|
||||
QIcon backIcon;
|
||||
backIcon.addFile(":/icons/icons/ui/angle-pointing-to-left.png");
|
||||
backBtn_->setIcon(backIcon);
|
||||
backBtn_->setIconSize(QSize(buttonSize_ / 2, buttonSize_ / 2));
|
||||
backBtn_->hide();
|
||||
|
||||
connect(backBtn_, &QPushButton::clicked, this, &TopRoomBar::showRoomList);
|
||||
|
||||
topLayout_->addWidget(avatar_);
|
||||
topLayout_->addWidget(backBtn_);
|
||||
topLayout_->addLayout(textLayout_, 1);
|
||||
topLayout_->addWidget(mentionsBtn_, 0, Qt::AlignRight);
|
||||
topLayout_->addWidget(settingsBtn_, 0, Qt::AlignRight);
|
||||
|
||||
menu_ = new Menu(this);
|
||||
|
||||
inviteUsers_ = new QAction(tr("Invite users"), this);
|
||||
connect(inviteUsers_, &QAction::triggered, this, [this]() {
|
||||
MainWindow::instance()->openInviteUsersDialog(
|
||||
[this](const QStringList &invitees) { emit inviteUsers(invitees); });
|
||||
});
|
||||
|
||||
roomMembers_ = new QAction(tr("Members"), this);
|
||||
connect(roomMembers_, &QAction::triggered, this, []() {
|
||||
MainWindow::instance()->openMemberListDialog();
|
||||
});
|
||||
|
||||
leaveRoom_ = new QAction(tr("Leave room"), this);
|
||||
connect(leaveRoom_, &QAction::triggered, this, []() {
|
||||
MainWindow::instance()->openLeaveRoomDialog();
|
||||
});
|
||||
|
||||
roomSettings_ = new QAction(tr("Settings"), this);
|
||||
connect(roomSettings_, &QAction::triggered, this, []() {
|
||||
MainWindow::instance()->openRoomSettings();
|
||||
});
|
||||
|
||||
menu_->addAction(inviteUsers_);
|
||||
menu_->addAction(roomMembers_);
|
||||
menu_->addAction(leaveRoom_);
|
||||
menu_->addAction(roomSettings_);
|
||||
|
||||
connect(settingsBtn_, &QPushButton::clicked, this, [this]() {
|
||||
auto pos = mapToGlobal(settingsBtn_->pos());
|
||||
menu_->popup(
|
||||
QPoint(pos.x() + buttonSize_ - menu_->sizeHint().width(), pos.y() + buttonSize_));
|
||||
});
|
||||
|
||||
connect(mentionsBtn_, &QPushButton::clicked, this, [this]() {
|
||||
auto pos = mapToGlobal(mentionsBtn_->pos());
|
||||
emit mentionsClicked(pos);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::enableBackButton()
|
||||
{
|
||||
avatar_->hide();
|
||||
backBtn_->show();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::disableBackButton()
|
||||
{
|
||||
avatar_->show();
|
||||
backBtn_->hide();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::updateRoomAvatarFromName(const QString &name)
|
||||
{
|
||||
avatar_->setLetter(utils::firstChar(name));
|
||||
update();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::reset()
|
||||
{
|
||||
nameLabel_->setText("");
|
||||
topicLabel_->setText("");
|
||||
avatar_->setLetter("");
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::updateRoomAvatar(const QString &avatar_image)
|
||||
{
|
||||
avatar_->setImage(avatar_image);
|
||||
update();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::updateRoomName(const QString &name)
|
||||
{
|
||||
nameLabel_->setText(name);
|
||||
update();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::updateRoomTopic(QString topic)
|
||||
{
|
||||
topic.replace(conf::strings::url_regex, conf::strings::url_html);
|
||||
topicLabel_->clearLinks();
|
||||
topicLabel_->setHtml(topic);
|
||||
update();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::mousePressEvent(QMouseEvent *)
|
||||
{
|
||||
if (roomSettings_ != nullptr)
|
||||
roomSettings_->trigger();
|
||||
}
|
||||
|
||||
void
|
||||
TopRoomBar::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QColor>
|
||||
#include <QStringList>
|
||||
#include <QWidget>
|
||||
|
||||
class Avatar;
|
||||
class FlatButton;
|
||||
class Menu;
|
||||
class TextLabel;
|
||||
class OverlayModal;
|
||||
|
||||
class QLabel;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
|
||||
class TopRoomBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor)
|
||||
|
||||
public:
|
||||
TopRoomBar(QWidget *parent = nullptr);
|
||||
|
||||
void updateRoomAvatar(const QString &avatar_image);
|
||||
void updateRoomName(const QString &name);
|
||||
void updateRoomTopic(QString topic);
|
||||
void updateRoomAvatarFromName(const QString &name);
|
||||
|
||||
void reset();
|
||||
|
||||
QColor borderColor() const { return borderColor_; }
|
||||
void setBorderColor(QColor &color) { borderColor_ = color; }
|
||||
|
||||
public slots:
|
||||
//! Add a "back-arrow" button that can switch to roomlist only view.
|
||||
void enableBackButton();
|
||||
//! Replace the "back-arrow" button with the avatar of the room.
|
||||
void disableBackButton();
|
||||
|
||||
signals:
|
||||
void inviteUsers(QStringList users);
|
||||
void showRoomList();
|
||||
void mentionsClicked(const QPoint &pos);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *) override;
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
private:
|
||||
QHBoxLayout *topLayout_ = nullptr;
|
||||
QVBoxLayout *textLayout_ = nullptr;
|
||||
|
||||
QLabel *nameLabel_ = nullptr;
|
||||
TextLabel *topicLabel_ = nullptr;
|
||||
|
||||
Menu *menu_;
|
||||
QAction *leaveRoom_ = nullptr;
|
||||
QAction *roomMembers_ = nullptr;
|
||||
QAction *roomSettings_ = nullptr;
|
||||
QAction *inviteUsers_ = nullptr;
|
||||
|
||||
FlatButton *settingsBtn_;
|
||||
FlatButton *mentionsBtn_;
|
||||
FlatButton *backBtn_;
|
||||
|
||||
Avatar *avatar_;
|
||||
|
||||
int buttonSize_;
|
||||
|
||||
QColor borderColor_;
|
||||
};
|
|
@ -517,6 +517,25 @@ TimelineModel::fetchMore(const QModelIndex &)
|
|||
events.fetchMore();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineModel::syncState(const mtx::responses::State &s)
|
||||
{
|
||||
using namespace mtx::events;
|
||||
|
||||
for (const auto &e : s.events) {
|
||||
if (std::holds_alternative<StateEvent<state::Avatar>>(e))
|
||||
emit roomAvatarUrlChanged();
|
||||
else if (std::holds_alternative<StateEvent<state::Name>>(e))
|
||||
emit roomNameChanged();
|
||||
else if (std::holds_alternative<StateEvent<state::Topic>>(e))
|
||||
emit roomTopicChanged();
|
||||
else if (std::holds_alternative<StateEvent<state::Member>>(e)) {
|
||||
emit roomAvatarUrlChanged();
|
||||
emit roomNameChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
||||
{
|
||||
|
@ -526,6 +545,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
|||
events.handleSync(timeline);
|
||||
|
||||
using namespace mtx::events;
|
||||
|
||||
for (auto e : timeline.events) {
|
||||
if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) {
|
||||
MegolmSessionIndex index;
|
||||
|
@ -549,6 +569,16 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline)
|
|||
emit newCallEvent(event);
|
||||
},
|
||||
e);
|
||||
else if (std::holds_alternative<StateEvent<state::Avatar>>(e))
|
||||
emit roomAvatarUrlChanged();
|
||||
else if (std::holds_alternative<StateEvent<state::Name>>(e))
|
||||
emit roomNameChanged();
|
||||
else if (std::holds_alternative<StateEvent<state::Topic>>(e))
|
||||
emit roomTopicChanged();
|
||||
else if (std::holds_alternative<StateEvent<state::Member>>(e)) {
|
||||
emit roomAvatarUrlChanged();
|
||||
emit roomNameChanged();
|
||||
}
|
||||
}
|
||||
updateLastMessage();
|
||||
}
|
||||
|
@ -1594,3 +1624,37 @@ TimelineModel::formatMemberEvent(QString id)
|
|||
|
||||
return rendered;
|
||||
}
|
||||
|
||||
QString
|
||||
TimelineModel::roomName() const
|
||||
{
|
||||
auto info = cache::getRoomInfo({room_id_.toStdString()});
|
||||
|
||||
if (!info.count(room_id_))
|
||||
return "";
|
||||
else
|
||||
return QString::fromStdString(info[room_id_].name);
|
||||
}
|
||||
|
||||
QString
|
||||
TimelineModel::roomAvatarUrl() const
|
||||
{
|
||||
auto info = cache::getRoomInfo({room_id_.toStdString()});
|
||||
|
||||
if (!info.count(room_id_))
|
||||
return "";
|
||||
else
|
||||
return QString::fromStdString(info[room_id_].avatar_url);
|
||||
}
|
||||
|
||||
QString
|
||||
TimelineModel::roomTopic() const
|
||||
{
|
||||
auto info = cache::getRoomInfo({room_id_.toStdString()});
|
||||
|
||||
if (!info.count(room_id_))
|
||||
return "";
|
||||
else
|
||||
return utils::replaceEmoji(utils::linkifyMessage(
|
||||
utils::escapeBlacklistedHtml(QString::fromStdString(info[room_id_].topic))));
|
||||
}
|
||||
|
|
|
@ -137,6 +137,9 @@ class TimelineModel : public QAbstractListModel
|
|||
Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply)
|
||||
Q_PROPERTY(
|
||||
bool paginationInProgress READ paginationInProgress NOTIFY paginationInProgressChanged)
|
||||
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
|
||||
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged)
|
||||
Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
|
||||
|
||||
public:
|
||||
explicit TimelineModel(TimelineViewManager *manager,
|
||||
|
@ -217,6 +220,7 @@ public:
|
|||
|
||||
void updateLastMessage();
|
||||
void addEvents(const mtx::responses::Timeline &events);
|
||||
void syncState(const mtx::responses::State &state);
|
||||
template<class T>
|
||||
void sendMessageEvent(const T &content, mtx::events::EventType eventType);
|
||||
RelatedInfo relatedInfo(QString id);
|
||||
|
@ -253,6 +257,10 @@ public slots:
|
|||
void setDecryptDescription(bool decrypt) { decryptDescription = decrypt; }
|
||||
void clearTimeline() { events.clearTimeline(); }
|
||||
|
||||
QString roomName() const;
|
||||
QString roomTopic() const;
|
||||
QString roomAvatarUrl() const;
|
||||
|
||||
private slots:
|
||||
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
||||
|
||||
|
@ -270,6 +278,10 @@ signals:
|
|||
void newMessageToSend(mtx::events::collections::TimelineEvents event);
|
||||
void addPendingMessageToStore(mtx::events::collections::TimelineEvents event);
|
||||
|
||||
void roomNameChanged();
|
||||
void roomTopicChanged();
|
||||
void roomAvatarUrlChanged();
|
||||
|
||||
private:
|
||||
void sendEncryptedMessageEvent(const std::string &txn_id,
|
||||
nlohmann::json content,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "ColorImageProvider.h"
|
||||
#include "DelegateChooser.h"
|
||||
#include "Logging.h"
|
||||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "MxcImageProvider.h"
|
||||
#include "UserSettingsPage.h"
|
||||
|
@ -76,7 +77,7 @@ TimelineViewManager::userStatus(QString id) const
|
|||
|
||||
TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettings,
|
||||
CallManager *callManager,
|
||||
QWidget *parent)
|
||||
ChatPage *parent)
|
||||
: imgProvider(new MxcImageProvider())
|
||||
, colorImgProvider(new ColorImageProvider())
|
||||
, blurhashProvider(new BlurhashProvider())
|
||||
|
@ -131,15 +132,12 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin
|
|||
view->engine()->addImageProvider("blurhash", blurhashProvider);
|
||||
view->setSource(QUrl("qrc:///qml/TimelineView.qml"));
|
||||
|
||||
connect(dynamic_cast<ChatPage *>(parent),
|
||||
&ChatPage::themeChanged,
|
||||
this,
|
||||
&TimelineViewManager::updateColorPalette);
|
||||
connect(dynamic_cast<ChatPage *>(parent),
|
||||
connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
|
||||
connect(parent,
|
||||
&ChatPage::decryptSidebarChanged,
|
||||
this,
|
||||
&TimelineViewManager::updateEncryptedDescriptions);
|
||||
connect(dynamic_cast<ChatPage *>(parent), &ChatPage::loggedOut, this, [this]() {
|
||||
connect(parent, &ChatPage::loggedOut, this, [this]() {
|
||||
isInitialSync_ = true;
|
||||
emit initialSyncChanged(true);
|
||||
});
|
||||
|
@ -157,6 +155,7 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
|
|||
&TimelineModel::newCallEvent,
|
||||
callManager_,
|
||||
&CallManager::syncEvent);
|
||||
room_model->syncState(room.state);
|
||||
room_model->addEvents(room.timeline);
|
||||
if (!isInitialSync_)
|
||||
disconnect(room_model.data(),
|
||||
|
@ -245,6 +244,28 @@ TimelineViewManager::openLink(QString link) const
|
|||
QDesktopServices::openUrl(link);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::openInviteUsersDialog()
|
||||
{
|
||||
MainWindow::instance()->openInviteUsersDialog(
|
||||
[this](const QStringList &invitees) { emit inviteUsers(invitees); });
|
||||
}
|
||||
void
|
||||
TimelineViewManager::openMemberListDialog() const
|
||||
{
|
||||
MainWindow::instance()->openMemberListDialog();
|
||||
}
|
||||
void
|
||||
TimelineViewManager::openLeaveRoomDialog() const
|
||||
{
|
||||
MainWindow::instance()->openLeaveRoomDialog();
|
||||
}
|
||||
void
|
||||
TimelineViewManager::openRoomSettings() const
|
||||
{
|
||||
MainWindow::instance()->openRoomSettings();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
||||
const std::vector<QString> &event_ids)
|
||||
|
|
|
@ -21,6 +21,7 @@ class BlurhashProvider;
|
|||
class CallManager;
|
||||
class ColorImageProvider;
|
||||
class UserSettings;
|
||||
class ChatPage;
|
||||
|
||||
class TimelineViewManager : public QObject
|
||||
{
|
||||
|
@ -30,11 +31,13 @@ class TimelineViewManager : public QObject
|
|||
TimelineModel *timeline MEMBER timeline_ READ activeTimeline NOTIFY activeTimelineChanged)
|
||||
Q_PROPERTY(
|
||||
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
|
||||
Q_PROPERTY(
|
||||
bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged)
|
||||
|
||||
public:
|
||||
TimelineViewManager(QSharedPointer<UserSettings> userSettings,
|
||||
CallManager *callManager,
|
||||
QWidget *parent = nullptr);
|
||||
ChatPage *parent = nullptr);
|
||||
QWidget *getWidget() const { return container; }
|
||||
|
||||
void sync(const mtx::responses::Rooms &rooms);
|
||||
|
@ -44,6 +47,7 @@ public:
|
|||
|
||||
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
|
||||
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
|
||||
bool isNarrowView() const { return isNarrowView_; }
|
||||
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const;
|
||||
Q_INVOKABLE QColor userColor(QString id, QColor background);
|
||||
|
||||
|
@ -52,6 +56,11 @@ public:
|
|||
|
||||
Q_INVOKABLE void openLink(QString link) const;
|
||||
|
||||
Q_INVOKABLE void openInviteUsersDialog();
|
||||
Q_INVOKABLE void openMemberListDialog() const;
|
||||
Q_INVOKABLE void openLeaveRoomDialog() const;
|
||||
Q_INVOKABLE void openRoomSettings() const;
|
||||
|
||||
signals:
|
||||
void clearRoomMessageCount(QString roomid);
|
||||
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
|
||||
|
@ -59,6 +68,9 @@ signals:
|
|||
void initialSyncChanged(bool isInitialSync);
|
||||
void replyingEventChanged(QString replyingEvent);
|
||||
void replyClosed();
|
||||
void inviteUsers(QStringList users);
|
||||
void showRoomList();
|
||||
void narrowViewChanged();
|
||||
|
||||
public slots:
|
||||
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||
|
@ -108,6 +120,23 @@ public slots:
|
|||
timeline_->clearTimeline();
|
||||
}
|
||||
|
||||
void enableBackButton()
|
||||
{
|
||||
if (isNarrowView_)
|
||||
return;
|
||||
isNarrowView_ = true;
|
||||
emit narrowViewChanged();
|
||||
}
|
||||
void disableBackButton()
|
||||
{
|
||||
if (!isNarrowView_)
|
||||
return;
|
||||
isNarrowView_ = false;
|
||||
emit narrowViewChanged();
|
||||
}
|
||||
|
||||
void backToRooms() { emit showRoomList(); }
|
||||
|
||||
private:
|
||||
#ifdef USE_QUICK_VIEW
|
||||
QQuickView *view;
|
||||
|
@ -125,6 +154,7 @@ private:
|
|||
CallManager *callManager_ = nullptr;
|
||||
|
||||
bool isInitialSync_ = true;
|
||||
bool isNarrowView_ = false;
|
||||
|
||||
QSharedPointer<UserSettings> settings;
|
||||
QHash<QString, QColor> userColors;
|
||||
|
|
Loading…
Reference in a new issue