From a7f8b23b524c5e3af72e42fde118706e94a454f3 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 13 May 2021 08:23:56 +0200 Subject: Make palette global in Qml --- src/ui/NhekoGlobalObject.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/ui/NhekoGlobalObject.cpp (limited to 'src/ui/NhekoGlobalObject.cpp') diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp new file mode 100644 index 00000000..5a2b9788 --- /dev/null +++ b/src/ui/NhekoGlobalObject.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "NhekoGlobalObject.h" + +#include "UserSettingsPage.h" + +Nheko::Nheko() +{ + connect( + UserSettings::instance().get(), &UserSettings::themeChanged, this, &Nheko::colorsChanged); +} + +QPalette +Nheko::colors() const +{ + return QPalette(); +} + +QPalette +Nheko::inactiveColors() const +{ + QPalette p; + p.setCurrentColorGroup(QPalette::ColorGroup::Inactive); + return p; +} -- cgit 1.5.1 From 22afa122c4697d25fd2f1eb4c7931bcf4ea43f31 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 13 May 2021 08:52:02 +0200 Subject: Move openLink to Nheko globals --- resources/qml/MatrixText.qml | 2 +- resources/qml/RoomSettings.qml | 2 +- src/timeline/TimelineViewManager.cpp | 51 ---------------------------------- src/timeline/TimelineViewManager.h | 2 -- src/ui/NhekoGlobalObject.cpp | 54 ++++++++++++++++++++++++++++++++++++ src/ui/NhekoGlobalObject.h | 3 ++ 6 files changed, 59 insertions(+), 55 deletions(-) (limited to 'src/ui/NhekoGlobalObject.cpp') diff --git a/resources/qml/MatrixText.qml b/resources/qml/MatrixText.qml index fa1cd98c..167899a5 100644 --- a/resources/qml/MatrixText.qml +++ b/resources/qml/MatrixText.qml @@ -14,7 +14,7 @@ TextEdit { selectByMouse: !Settings.mobileMode enabled: selectByMouse color: Nheko.colors.text - onLinkActivated: TimelineManager.openLink(link) + onLinkActivated: Nheko.openLink(link) ToolTip.visible: hoveredLink ToolTip.text: hoveredLink diff --git a/resources/qml/RoomSettings.qml b/resources/qml/RoomSettings.qml index ba577f33..14de0edf 100644 --- a/resources/qml/RoomSettings.qml +++ b/resources/qml/RoomSettings.qml @@ -128,7 +128,7 @@ ApplicationWindow { selectByMouse: true color: Nheko.colors.text horizontalAlignment: TextEdit.AlignHCenter - onLinkActivated: TimelineManager.openLink(link) + onLinkActivated: Nheko.openLink(link) CursorShape { anchors.fill: parent diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 94cef1a7..b407a128 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -4,7 +4,6 @@ #include "TimelineViewManager.h" -#include #include #include #include @@ -476,56 +475,6 @@ TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img) }); } -void -TimelineViewManager::openLink(QString link) const -{ - QUrl url(link); - if (url.scheme() == "https" && url.host() == "matrix.to") { - // handle matrix.to links internally - QString p = url.fragment(QUrl::FullyEncoded); - if (p.startsWith("/")) - p.remove(0, 1); - - auto temp = p.split("?"); - QString query; - if (temp.size() >= 2) - query = QUrl::fromPercentEncoding(temp.takeAt(1).toUtf8()); - - temp = temp.first().split("/"); - auto identifier = QUrl::fromPercentEncoding(temp.takeFirst().toUtf8()); - QString eventId = QUrl::fromPercentEncoding(temp.join('/').toUtf8()); - if (!identifier.isEmpty()) { - if (identifier.startsWith("@")) { - QByteArray uri = - "matrix:u/" + QUrl::toPercentEncoding(identifier.remove(0, 1)); - if (!query.isEmpty()) - uri.append("?" + query.toUtf8()); - ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); - } else if (identifier.startsWith("#")) { - QByteArray uri = - "matrix:r/" + QUrl::toPercentEncoding(identifier.remove(0, 1)); - if (!eventId.isEmpty()) - uri.append("/e/" + - QUrl::toPercentEncoding(eventId.remove(0, 1))); - if (!query.isEmpty()) - uri.append("?" + query.toUtf8()); - ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); - } else if (identifier.startsWith("!")) { - QByteArray uri = "matrix:roomid/" + - QUrl::toPercentEncoding(identifier.remove(0, 1)); - if (!eventId.isEmpty()) - uri.append("/e/" + - QUrl::toPercentEncoding(eventId.remove(0, 1))); - if (!query.isEmpty()) - uri.append("?" + query.toUtf8()); - ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); - } - } - } else { - QDesktopServices::openUrl(url); - } -} - void TimelineViewManager::openInviteUsersDialog() { diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index b23a61db..0665b663 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -68,8 +68,6 @@ public: Q_INVOKABLE QString userPresence(QString id) const; Q_INVOKABLE QString userStatus(QString id) const; - Q_INVOKABLE void openLink(QString link) const; - Q_INVOKABLE void focusMessageInput(); Q_INVOKABLE void openInviteUsersDialog(); Q_INVOKABLE void openMemberListDialog() const; diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index 5a2b9788..e5e6825e 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -4,6 +4,10 @@ #include "NhekoGlobalObject.h" +#include +#include + +#include "ChatPage.h" #include "UserSettingsPage.h" Nheko::Nheko() @@ -25,3 +29,53 @@ Nheko::inactiveColors() const p.setCurrentColorGroup(QPalette::ColorGroup::Inactive); return p; } + +void +Nheko::openLink(QString link) const +{ + QUrl url(link); + if (url.scheme() == "https" && url.host() == "matrix.to") { + // handle matrix.to links internally + QString p = url.fragment(QUrl::FullyEncoded); + if (p.startsWith("/")) + p.remove(0, 1); + + auto temp = p.split("?"); + QString query; + if (temp.size() >= 2) + query = QUrl::fromPercentEncoding(temp.takeAt(1).toUtf8()); + + temp = temp.first().split("/"); + auto identifier = QUrl::fromPercentEncoding(temp.takeFirst().toUtf8()); + QString eventId = QUrl::fromPercentEncoding(temp.join('/').toUtf8()); + if (!identifier.isEmpty()) { + if (identifier.startsWith("@")) { + QByteArray uri = + "matrix:u/" + QUrl::toPercentEncoding(identifier.remove(0, 1)); + if (!query.isEmpty()) + uri.append("?" + query.toUtf8()); + ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); + } else if (identifier.startsWith("#")) { + QByteArray uri = + "matrix:r/" + QUrl::toPercentEncoding(identifier.remove(0, 1)); + if (!eventId.isEmpty()) + uri.append("/e/" + + QUrl::toPercentEncoding(eventId.remove(0, 1))); + if (!query.isEmpty()) + uri.append("?" + query.toUtf8()); + ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); + } else if (identifier.startsWith("!")) { + QByteArray uri = "matrix:roomid/" + + QUrl::toPercentEncoding(identifier.remove(0, 1)); + if (!eventId.isEmpty()) + uri.append("/e/" + + QUrl::toPercentEncoding(eventId.remove(0, 1))); + if (!query.isEmpty()) + uri.append("?" + query.toUtf8()); + ChatPage::instance()->handleMatrixUri(QUrl::fromEncoded(uri)); + } + } + } else { + QDesktopServices::openUrl(url); + } +} diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h index 76186828..05a0c050 100644 --- a/src/ui/NhekoGlobalObject.h +++ b/src/ui/NhekoGlobalObject.h @@ -20,6 +20,9 @@ public: QPalette colors() const; QPalette inactiveColors() const; + Q_INVOKABLE void openLink(QString link) const; + signals: void colorsChanged(); }; + -- cgit 1.5.1 From 567fe81ad78e707a4b914976a92c855d4ac8fc45 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 14 May 2021 23:35:34 +0200 Subject: Basic header and footer of room list --- resources/qml/ChatPage.qml | 17 ++-- resources/qml/RoomList.qml | 183 +++++++++++++++++++++++++++++++++++++++++ resources/qml/TimelineView.qml | 4 +- resources/qml/TopBar.qml | 4 +- resources/res.qrc | 1 + src/Cache.cpp | 31 +++++-- src/Cache_p.h | 3 + src/CommunitiesList.h | 1 - src/CommunitiesListItem.h | 1 - src/MainWindow.cpp | 1 + src/MainWindow.h | 1 + src/UserSettingsPage.cpp | 37 +-------- src/ui/NhekoGlobalObject.cpp | 33 +++++++- src/ui/NhekoGlobalObject.h | 16 +++- src/ui/Theme.cpp | 117 ++++++++++++-------------- src/ui/Theme.h | 38 +++------ src/ui/ThemeManager.cpp | 39 ++++++--- src/ui/ThemeManager.h | 5 -- src/ui/UserProfile.cpp | 28 ++++--- 19 files changed, 385 insertions(+), 175 deletions(-) create mode 100644 resources/qml/RoomList.qml (limited to 'src/ui/NhekoGlobalObject.cpp') diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml index a02f0ca9..fc6137a6 100644 --- a/resources/qml/ChatPage.qml +++ b/resources/qml/ChatPage.qml @@ -19,14 +19,14 @@ Rectangle { SplitView.minimumWidth: Nheko.avatarSize + Nheko.paddingSmall * 2 SplitView.preferredWidth: Nheko.avatarSize + Nheko.paddingSmall * 2 SplitView.maximumWidth: Nheko.avatarSize + Nheko.paddingSmall * 2 - color: "blue" + color: Nheko.theme.sidebarBackground } - Rectangle { - SplitView.minimumWidth: Nheko.avatarSize * 3 + Nheko.paddingSmall * 2 - SplitView.preferredWidth: Nheko.avatarSize * 3 + Nheko.paddingSmall * 2 - SplitView.maximumWidth: Nheko.avatarSize * 7 + Nheko.paddingSmall * 2 - color: "red" + RoomList { + //SplitView.maximumWidth: Nheko.avatarSize * 7 + Nheko.paddingSmall * 2 + + SplitView.minimumWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2 + SplitView.preferredWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2 } TimelineView { @@ -36,6 +36,11 @@ Rectangle { SplitView.minimumWidth: 400 } + handle: Rectangle { + implicitWidth: 2 + color: SplitHandle.pressed ? Nheko.colors.highlight : (SplitHandle.hovered ? Nheko.colors.light : Nheko.theme.separator) + } + } PrivacyScreen { diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml new file mode 100644 index 00000000..25abb4d1 --- /dev/null +++ b/resources/qml/RoomList.qml @@ -0,0 +1,183 @@ +// SPDX-FileCopyrightText: 2021 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.9 +import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.3 +import im.nheko 1.0 + +Page { + + background: Rectangle { + color: Nheko.theme.sidebarBackground + } + + header: ColumnLayout { + spacing: 0 + + Rectangle { + color: Nheko.colors.window + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium + Layout.minimumHeight: 40 + + RowLayout { + id: userInfoGrid + + spacing: Nheko.paddingMedium + anchors.fill: parent + anchors.margins: Nheko.paddingMedium + + Avatar { + id: avatar + + Layout.alignment: Qt.AlignVCenter + Layout.preferredWidth: Nheko.avatarSize + Layout.preferredHeight: Nheko.avatarSize + url: Nheko.currentUser.avatarUrl.replace("mxc://", "image://MxcImage/") + displayName: Nheko.currentUser.displayName + userid: Nheko.currentUser.userid + } + + ColumnLayout { + id: col + + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.minimumWidth: 100 + width: parent.width - avatar.width - logoutButton.width + Layout.preferredWidth: parent.width - avatar.width - logoutButton.width + spacing: 0 + + Label { + Layout.alignment: Qt.AlignBottom + color: Nheko.colors.text + font.pointSize: fontMetrics.font.pointSize * 1.1 + font.weight: Font.DemiBold + text: userNameText.elidedText + maximumLineCount: 1 + 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 { + Layout.alignment: Qt.AlignTop + color: Nheko.colors.buttonText + font.weight: Font.Thin + text: userIdText.elidedText + maximumLineCount: 1 + textFormat: Text.PlainText + font.pointSize: fontMetrics.font.pointSize * 0.9 + + TextMetrics { + id: userIdText + + font.pointSize: fontMetrics.font.pointSize * 0.9 + elide: Text.ElideRight + elideWidth: col.width + text: Nheko.currentUser.userid + } + + } + + } + + Item { + } + + ImageButton { + id: logoutButton + + Layout.alignment: Qt.AlignVCenter + image: ":/icons/icons/ui/power-button-off.png" + ToolTip.visible: hovered + ToolTip.text: qsTr("Logout") + } + + } + + } + + Rectangle { + color: Nheko.theme.separator + height: 2 + Layout.fillWidth: true + } + + } + + footer: ColumnLayout { + spacing: 0 + + Rectangle { + color: Nheko.theme.separator + height: 1 + Layout.fillWidth: true + } + + Rectangle { + color: Nheko.colors.window + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + Layout.preferredHeight: buttonRow.implicitHeight + Layout.minimumHeight: 40 + + RowLayout { + id: buttonRow + + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Nheko.paddingMedium + + ImageButton { + Layout.alignment: Qt.AlignBottom | Qt.AlignLeft + hoverEnabled: true + width: 22 + height: 22 + image: ":/icons/icons/ui/plus-black-symbol.png" + ToolTip.visible: hovered + ToolTip.text: qsTr("Start a new chat") + Layout.margins: Nheko.paddingMedium + } + + ImageButton { + Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter + hoverEnabled: true + width: 22 + height: 22 + image: ":/icons/icons/ui/speech-bubbles-comment-option.png" + ToolTip.visible: hovered + ToolTip.text: qsTr("Room directory") + Layout.margins: Nheko.paddingMedium + } + + ImageButton { + Layout.alignment: Qt.AlignBottom | Qt.AlignRight + hoverEnabled: true + width: 22 + height: 22 + image: ":/icons/icons/ui/settings.png" + ToolTip.visible: hovered + ToolTip.text: qsTr("User settings") + Layout.margins: Nheko.paddingMedium + } + + } + + } + + } + +} diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 0d0e286d..257d670d 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -49,7 +49,7 @@ Item { Layout.fillWidth: true height: 1 z: 3 - color: Nheko.colors.mid + color: Nheko.theme.separator } Rectangle { @@ -112,7 +112,7 @@ Item { Layout.fillWidth: true z: 3 height: 1 - color: Nheko.colors.mid + color: Nheko.theme.separator } ReplyPopup { diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index d5bcb3a8..bda5ce14 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -14,7 +14,7 @@ Rectangle { property var room: TimelineManager.timeline Layout.fillWidth: true - implicitHeight: topLayout.height + 16 + implicitHeight: topLayout.height + Nheko.paddingMedium * 2 z: 3 color: Nheko.colors.window @@ -33,7 +33,7 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - anchors.margins: 8 + anchors.margins: Nheko.paddingMedium anchors.verticalCenter: parent.verticalCenter ImageButton { diff --git a/resources/res.qrc b/resources/res.qrc index 8105e966..c146f2d9 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -125,6 +125,7 @@ qml/Root.qml qml/ChatPage.qml + qml/RoomList.qml qml/TimelineView.qml qml/Avatar.qml qml/Completer.qml diff --git a/src/Cache.cpp b/src/Cache.cpp index 24b2bc24..d8c78381 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -253,6 +253,8 @@ Cache::setup() outboundMegolmSessionDb_ = lmdb::dbi::open(txn, OUTBOUND_MEGOLM_SESSIONS_DB, MDB_CREATE); txn.commit(); + + databaseReady_ = true; } void @@ -788,6 +790,7 @@ Cache::nextBatchToken() void Cache::deleteData() { + this->databaseReady_ = false; // TODO: We need to remove the env_ while not accepting new requests. lmdb::dbi_close(env_, syncStateDb_); lmdb::dbi_close(env_, roomsDb_); @@ -2426,7 +2429,7 @@ Cache::joinedRooms() std::optional Cache::getMember(const std::string &room_id, const std::string &user_id) { - if (user_id.empty()) + if (user_id.empty() || !env_.handle()) return std::nullopt; try { @@ -3551,8 +3554,8 @@ Cache::query_keys(const std::string &user_id, http::client()->query_keys( req, - [cb, user_id, last_changed](const mtx::responses::QueryKeys &res, - mtx::http::RequestErr err) { + [cb, user_id, last_changed, this](const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err) { if (err) { nhlog::net()->warn("failed to query device keys: {},{}", mtx::errors::to_string(err->matrix_error.errcode), @@ -3561,10 +3564,22 @@ Cache::query_keys(const std::string &user_id, return; } - cache::updateUserKeys(last_changed, res); - - auto keys = cache::userKeys(user_id); - cb(keys.value_or(UserKeyCache{}), err); + emit userKeysUpdate(last_changed, res); + + // use context object so that we can disconnect again + std::unique_ptr context{new QObject}; + QObject *pcontext = context.get(); + QObject::connect( + this, + &Cache::verificationStatusChanged, + pcontext, + [cb, user_id, context_ = std::move(context)](std::string updated_user) mutable { + if (user_id == updated_user) { + context_.release(); + auto keys = cache::userKeys(user_id); + cb(keys.value_or(UserKeyCache{}), {}); + } + }); }); } @@ -3999,6 +4014,8 @@ avatarUrl(const QString &room_id, const QString &user_id) mtx::presence::PresenceState presenceState(const std::string &user_id) { + if (!instance_) + return {}; return instance_->presenceState(user_id); } std::string diff --git a/src/Cache_p.h b/src/Cache_p.h index 356c6e42..c55fa601 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -100,6 +100,7 @@ public: void saveState(const mtx::responses::Sync &res); bool isInitialized(); + bool isDatabaseReady() { return databaseReady_ && isInitialized(); } std::string nextBatchToken(); @@ -620,6 +621,8 @@ private: QString cacheDirectory_; VerificationStorage verification_storage; + + bool databaseReady_ = false; }; namespace cache { diff --git a/src/CommunitiesList.h b/src/CommunitiesList.h index 2586f6f5..12b275b0 100644 --- a/src/CommunitiesList.h +++ b/src/CommunitiesList.h @@ -10,7 +10,6 @@ #include "CacheStructs.h" #include "CommunitiesListItem.h" -#include "ui/Theme.h" namespace mtx::responses { struct GroupProfile; diff --git a/src/CommunitiesListItem.h b/src/CommunitiesListItem.h index 006511c8..e7468611 100644 --- a/src/CommunitiesListItem.h +++ b/src/CommunitiesListItem.h @@ -10,7 +10,6 @@ #include #include "Config.h" -#include "ui/Theme.h" class RippleOverlay; class QMouseEvent; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 92f43e03..e2b625b0 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -295,6 +295,7 @@ MainWindow::showChatPage() &Cache::secretChanged, userSettingsPage_, &UserSettingsPage::updateSecretStatus); + emit reload(); } void diff --git a/src/MainWindow.h b/src/MainWindow.h index 4122e4c1..69d07e62 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -109,6 +109,7 @@ private slots: signals: void focusChanged(const bool focused); + void reload(); private: bool loadJdenticonPlugin(); diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index 0edc1288..99560678 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -545,49 +545,14 @@ UserSettings::applyTheme() { QFile stylefile; - static QPalette original; if (this->theme() == "light") { stylefile.setFileName(":/styles/styles/nheko.qss"); - QPalette lightActive( - /*windowText*/ QColor("#333"), - /*button*/ QColor("white"), - /*light*/ QColor(0xef, 0xef, 0xef), - /*dark*/ QColor(110, 110, 110), - /*mid*/ QColor(220, 220, 220), - /*text*/ QColor("#333"), - /*bright_text*/ QColor("#333"), - /*base*/ QColor("#fff"), - /*window*/ QColor("white")); - lightActive.setColor(QPalette::AlternateBase, QColor("#eee")); - lightActive.setColor(QPalette::Highlight, QColor("#38a3d8")); - lightActive.setColor(QPalette::ToolTipBase, lightActive.base().color()); - lightActive.setColor(QPalette::ToolTipText, lightActive.text().color()); - lightActive.setColor(QPalette::Link, QColor("#0077b5")); - lightActive.setColor(QPalette::ButtonText, QColor("#333")); - QApplication::setPalette(lightActive); } else if (this->theme() == "dark") { stylefile.setFileName(":/styles/styles/nheko-dark.qss"); - QPalette darkActive( - /*windowText*/ QColor("#caccd1"), - /*button*/ QColor(0xff, 0xff, 0xff), - /*light*/ QColor("#caccd1"), - /*dark*/ QColor(110, 110, 110), - /*mid*/ QColor("#202228"), - /*text*/ QColor("#caccd1"), - /*bright_text*/ QColor(0xff, 0xff, 0xff), - /*base*/ QColor("#202228"), - /*window*/ QColor("#2d3139")); - darkActive.setColor(QPalette::AlternateBase, QColor("#2d3139")); - darkActive.setColor(QPalette::Highlight, QColor("#38a3d8")); - darkActive.setColor(QPalette::ToolTipBase, darkActive.base().color()); - darkActive.setColor(QPalette::ToolTipText, darkActive.text().color()); - darkActive.setColor(QPalette::Link, QColor("#38a3d8")); - darkActive.setColor(QPalette::ButtonText, "#727274"); - QApplication::setPalette(darkActive); } else { stylefile.setFileName(":/styles/styles/system.qss"); - QApplication::setPalette(original); } + QApplication::setPalette(Theme::paletteFromTheme(this->theme().toStdString())); stylefile.open(QFile::ReadOnly); QString stylesheet = QString(stylefile.readAll()); diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index e5e6825e..70abfbb8 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -7,29 +7,50 @@ #include #include +#include "Cache_p.h" #include "ChatPage.h" +#include "Logging.h" #include "UserSettingsPage.h" +#include "Utils.h" Nheko::Nheko() { connect( UserSettings::instance().get(), &UserSettings::themeChanged, this, &Nheko::colorsChanged); + connect(ChatPage::instance(), &ChatPage::contentLoaded, this, &Nheko::updateUserProfile); +} + +void +Nheko::updateUserProfile() +{ + if (cache::client() && cache::client()->isInitialized()) + currentUser_.reset( + new UserProfile("", utils::localUser(), ChatPage::instance()->timelineManager())); + else + currentUser_.reset(); + emit profileChanged(); } QPalette Nheko::colors() const { - return QPalette(); + return Theme::paletteFromTheme(UserSettings::instance()->theme().toStdString()); } QPalette Nheko::inactiveColors() const { - QPalette p; + auto p = colors(); p.setCurrentColorGroup(QPalette::ColorGroup::Inactive); return p; } +Theme +Nheko::theme() const +{ + return Theme(UserSettings::instance()->theme().toStdString()); +} + void Nheko::openLink(QString link) const { @@ -79,3 +100,11 @@ Nheko::openLink(QString link) const QDesktopServices::openUrl(url); } } + +UserProfile * +Nheko::currentUser() const +{ + nhlog::ui()->debug("Profile requested"); + + return currentUser_.get(); +} diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h index d952c266..fe645a34 100644 --- a/src/ui/NhekoGlobalObject.h +++ b/src/ui/NhekoGlobalObject.h @@ -7,32 +7,46 @@ #include #include +#include "Theme.h" +#include "UserProfile.h" + class Nheko : public QObject { Q_OBJECT Q_PROPERTY(QPalette colors READ colors NOTIFY colorsChanged) Q_PROPERTY(QPalette inactiveColors READ inactiveColors NOTIFY colorsChanged) + Q_PROPERTY(Theme theme READ theme NOTIFY colorsChanged) Q_PROPERTY(int avatarSize READ avatarSize CONSTANT) Q_PROPERTY(int paddingSmall READ paddingSmall CONSTANT) Q_PROPERTY(int paddingMedium READ paddingMedium CONSTANT) Q_PROPERTY(int paddingLarge READ paddingLarge CONSTANT) + Q_PROPERTY(UserProfile *currentUser READ currentUser NOTIFY profileChanged) + public: Nheko(); QPalette colors() const; QPalette inactiveColors() const; + Theme theme() const; int avatarSize() const { return 40; } int paddingSmall() const { return 4; } int paddingMedium() const { return 8; } int paddingLarge() const { return 20; } + UserProfile *currentUser() const; Q_INVOKABLE void openLink(QString link) const; +private slots: + void updateUserProfile(); + signals: void colorsChanged(); -}; + void profileChanged(); +private: + QScopedPointer currentUser_; +}; diff --git a/src/ui/Theme.cpp b/src/ui/Theme.cpp index 4341bd63..ca2a4ce0 100644 --- a/src/ui/Theme.cpp +++ b/src/ui/Theme.cpp @@ -2,76 +2,65 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -#include - #include "Theme.h" -Theme::Theme(QObject *parent) - : QObject(parent) -{ - setColor("Black", ui::Color::Black); - - setColor("BrightWhite", ui::Color::BrightWhite); - setColor("FadedWhite", ui::Color::FadedWhite); - setColor("MediumWhite", ui::Color::MediumWhite); - - setColor("BrightGreen", ui::Color::BrightGreen); - setColor("DarkGreen", ui::Color::DarkGreen); - setColor("LightGreen", ui::Color::LightGreen); - - setColor("Gray", ui::Color::Gray); - setColor("Red", ui::Color::Red); - setColor("Blue", ui::Color::Blue); - - setColor("Transparent", ui::Color::Transparent); -} - -QColor -Theme::rgba(int r, int g, int b, qreal a) const -{ - QColor color(r, g, b); - color.setAlphaF(a); - - return color; -} +Q_DECLARE_METATYPE(Theme) -QColor -Theme::getColor(const QString &key) const +QPalette +Theme::paletteFromTheme(std::string_view theme) { - if (!colors_.contains(key)) { - qWarning() << "Color with key" << key << "could not be found"; - return QColor(); + [[maybe_unused]] static auto meta = qRegisterMetaType("Theme"); + static QPalette original; + if (theme == "light") { + QPalette lightActive( + /*windowText*/ QColor("#333"), + /*button*/ QColor("white"), + /*light*/ QColor(0xef, 0xef, 0xef), + /*dark*/ QColor(110, 110, 110), + /*mid*/ QColor(220, 220, 220), + /*text*/ QColor("#333"), + /*bright_text*/ QColor("#333"), + /*base*/ QColor("#fff"), + /*window*/ QColor("white")); + lightActive.setColor(QPalette::AlternateBase, QColor("#eee")); + lightActive.setColor(QPalette::Highlight, QColor("#38a3d8")); + lightActive.setColor(QPalette::ToolTipBase, lightActive.base().color()); + lightActive.setColor(QPalette::ToolTipText, lightActive.text().color()); + lightActive.setColor(QPalette::Link, QColor("#0077b5")); + lightActive.setColor(QPalette::ButtonText, QColor("#555459")); + return lightActive; + } else if (theme == "dark") { + QPalette darkActive( + /*windowText*/ QColor("#caccd1"), + /*button*/ QColor(0xff, 0xff, 0xff), + /*light*/ QColor("#caccd1"), + /*dark*/ QColor(110, 110, 110), + /*mid*/ QColor("#202228"), + /*text*/ QColor("#caccd1"), + /*bright_text*/ QColor(0xff, 0xff, 0xff), + /*base*/ QColor("#202228"), + /*window*/ QColor("#2d3139")); + darkActive.setColor(QPalette::AlternateBase, QColor("#2d3139")); + darkActive.setColor(QPalette::Highlight, QColor("#38a3d8")); + darkActive.setColor(QPalette::ToolTipBase, darkActive.base().color()); + darkActive.setColor(QPalette::ToolTipText, darkActive.text().color()); + darkActive.setColor(QPalette::Link, QColor("#38a3d8")); + darkActive.setColor(QPalette::ButtonText, "#727274"); + return darkActive; + } else { + return original; } - - return colors_.value(key); } -void -Theme::setColor(const QString &key, const QColor &color) +Theme::Theme(std::string_view theme) { - colors_.insert(key, color); -} - -void -Theme::setColor(const QString &key, ui::Color color) -{ - static const QColor palette[] = { - QColor("#171919"), - - QColor("#EBEBEB"), - QColor("#C9C9C9"), - QColor("#929292"), - - QColor("#1C3133"), - QColor("#577275"), - QColor("#46A451"), - - QColor("#5D6565"), - QColor("#E22826"), - QColor("#81B3A9"), - - rgba(0, 0, 0, 0), - }; - - colors_.insert(key, palette[static_cast(color)]); + auto p = paletteFromTheme(theme); + separator_ = p.mid().color(); + if (theme == "light") { + sidebarBackground_ = QColor("#233649"); + } else if (theme == "dark") { + sidebarBackground_ = QColor("#2d3139"); + } else { + sidebarBackground_ = p.window().color(); + } } diff --git a/src/ui/Theme.h b/src/ui/Theme.h index 3243c076..64bc8273 100644 --- a/src/ui/Theme.h +++ b/src/ui/Theme.h @@ -5,8 +5,7 @@ #pragma once #include -#include -#include +#include namespace ui { enum class AvatarType @@ -60,36 +59,21 @@ enum class ProgressType IndeterminateProgress }; -enum class Color -{ - Black, - BrightWhite, - FadedWhite, - MediumWhite, - DarkGreen, - LightGreen, - BrightGreen, - Gray, - Red, - Blue, - Transparent -}; - } // namespace ui -class Theme : public QObject +class Theme : public QPalette { - Q_OBJECT + Q_GADGET + Q_PROPERTY(QColor sidebarBackground READ sidebarBackground CONSTANT) + Q_PROPERTY(QColor separator READ separator CONSTANT) public: - explicit Theme(QObject *parent = nullptr); + Theme() {} + explicit Theme(std::string_view theme); + static QPalette paletteFromTheme(std::string_view theme); - QColor getColor(const QString &key) const; - - void setColor(const QString &key, const QColor &color); - void setColor(const QString &key, ui::Color color); + QColor sidebarBackground() const { return sidebarBackground_; } + QColor separator() const { return separator_; } private: - QColor rgba(int r, int g, int b, qreal a) const; - - QHash colors_; + QColor sidebarBackground_, separator_; }; diff --git a/src/ui/ThemeManager.cpp b/src/ui/ThemeManager.cpp index 834f5083..b7b3df40 100644 --- a/src/ui/ThemeManager.cpp +++ b/src/ui/ThemeManager.cpp @@ -6,18 +6,37 @@ #include "ThemeManager.h" -ThemeManager::ThemeManager() { setTheme(new Theme); } - -void -ThemeManager::setTheme(Theme *theme) -{ - theme_ = theme; - theme_->setParent(this); -} +ThemeManager::ThemeManager() {} QColor ThemeManager::themeColor(const QString &key) const { - Q_ASSERT(theme_); - return theme_->getColor(key); + if (key == "Black") + return QColor("#171919"); + + else if (key == "BrightWhite") + return QColor("#EBEBEB"); + else if (key == "FadedWhite") + return QColor("#C9C9C9"); + else if (key == "MediumWhite") + return QColor("#929292"); + + else if (key == "BrightGreen") + return QColor("#1C3133"); + else if (key == "DarkGreen") + return QColor("#577275"); + else if (key == "LightGreen") + return QColor("#46A451"); + + else if (key == "Gray") + return QColor("#5D6565"); + else if (key == "Red") + return QColor("#E22826"); + else if (key == "Blue") + return QColor("#81B3A9"); + + else if (key == "Transparent") + return QColor(0, 0, 0, 0); + + return (QColor(0, 0, 0, 0)); } diff --git a/src/ui/ThemeManager.h b/src/ui/ThemeManager.h index f2099730..cbb355fd 100644 --- a/src/ui/ThemeManager.h +++ b/src/ui/ThemeManager.h @@ -6,8 +6,6 @@ #include -#include "Theme.h" - class ThemeManager : public QCommonStyle { Q_OBJECT @@ -15,7 +13,6 @@ class ThemeManager : public QCommonStyle public: inline static ThemeManager &instance(); - void setTheme(Theme *theme); QColor themeColor(const QString &key) const; private: @@ -23,8 +20,6 @@ private: ThemeManager(ThemeManager const &); void operator=(ThemeManager const &); - - Theme *theme_; }; inline ThemeManager & diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 0f330964..cef8bd85 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -27,9 +27,22 @@ UserProfile::UserProfile(QString roomid, , manager(manager_) , model(parent) { - fetchDeviceList(this->userid_); globalAvatarUrl = ""; + connect(this, + &UserProfile::globalUsernameRetrieved, + this, + &UserProfile::setGlobalUsername, + Qt::QueuedConnection); + + if (isGlobalUserProfile()) { + getGlobalProfileData(); + } + + if (!cache::client() || !cache::client()->isDatabaseReady()) + return; + + fetchDeviceList(this->userid_); connect(cache::client(), &Cache::verificationStatusChanged, this, @@ -54,16 +67,6 @@ UserProfile::UserProfile(QString roomid, } deviceList_.reset(deviceList_.deviceList_); }); - - connect(this, - &UserProfile::globalUsernameRetrieved, - this, - &UserProfile::setGlobalUsername, - Qt::QueuedConnection); - - if (isGlobalUserProfile()) { - getGlobalProfileData(); - } } QHash @@ -157,6 +160,9 @@ UserProfile::fetchDeviceList(const QString &userID) { auto localUser = utils::localUser(); + if (!cache::client() || !cache::client()->isDatabaseReady()) + return; + cache::client()->query_keys( userID.toStdString(), [other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys, -- cgit 1.5.1 From 6112badb087e424d6a6f82301922ccd2c93e178c Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 22 May 2021 15:19:44 +0200 Subject: Reenable userInfo settings menu --- resources/qml/MatrixTextField.qml | 1 + resources/qml/RoomList.qml | 82 +++++++++++++++++++++++++++++++++++---- src/ui/NhekoGlobalObject.cpp | 5 +++ src/ui/NhekoGlobalObject.h | 1 + 4 files changed, 82 insertions(+), 7 deletions(-) (limited to 'src/ui/NhekoGlobalObject.cpp') diff --git a/resources/qml/MatrixTextField.qml b/resources/qml/MatrixTextField.qml index 2ba648b5..3c660bac 100644 --- a/resources/qml/MatrixTextField.qml +++ b/resources/qml/MatrixTextField.qml @@ -11,6 +11,7 @@ TextField { id: input palette: Nheko.colors + color: Nheko.colors.text Rectangle { id: blueBar diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index cde744c5..40669eda 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +import Qt.labs.platform 1.1 as Platform import QtQuick 2.13 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.3 @@ -206,20 +207,87 @@ Page { spacing: 0 Rectangle { + id: userInfoPanel + + function openUserProfile() { + Nheko.updateUserProfile(); + var userProfile = userProfileComponent.createObject(timelineRoot, { + "profile": Nheko.currentUser + }); + userProfile.show(); + } + color: Nheko.colors.window Layout.fillWidth: true Layout.alignment: Qt.AlignBottom Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium Layout.minimumHeight: 40 - TapHandler { - onSingleTapped: { - Nheko.updateUserProfile(); - var userProfile = userProfileComponent.createObject(timelineRoot, { - "profile": Nheko.currentUser - }); - userProfile.show(); + ApplicationWindow { + id: statusDialog + + modality: Qt.NonModal + flags: Qt.Dialog + title: qsTr("Status Message") + width: 350 + height: fontMetrics.lineSpacing * 7 + + ColumnLayout { + anchors.margins: Nheko.paddingLarge + anchors.fill: parent + + Label { + color: Nheko.colors.text + text: qsTr("Enter your status message:") + } + + MatrixTextField { + id: statusInput + + Layout.fillWidth: true + } + } + + footer: DialogButtonBox { + standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel + onAccepted: { + Nheko.setStatusMessage(statusInput.text); + statusDialog.close(); + } + onRejected: { + statusDialog.close(); + } + } + + } + + Platform.Menu { + id: userInfoMenu + + Platform.MenuItem { + text: qsTr("Profile settings") + onTriggered: userInfoPanel.openUserProfile() + } + + Platform.MenuItem { + text: qsTr("Set status message") + onTriggered: statusDialog.show() + } + + } + + TapHandler { + acceptedButtons: Qt.LeftButton + onSingleTapped: userInfoPanel.openUserProfile() + onLongPressed: userInfoMenu.open() + gesturePolicy: TapHandler.ReleaseWithinBounds + } + + TapHandler { + acceptedButtons: Qt.RightButton + onSingleTapped: userInfoMenu.open() + gesturePolicy: TapHandler.ReleaseWithinBounds } RowLayout { diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index 70abfbb8..fd572b4b 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -100,6 +100,11 @@ Nheko::openLink(QString link) const QDesktopServices::openUrl(url); } } +void +Nheko::setStatusMessage(QString msg) const +{ + ChatPage::instance()->setStatus(msg); +} UserProfile * Nheko::currentUser() const diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h index fc35fe22..593514fa 100644 --- a/src/ui/NhekoGlobalObject.h +++ b/src/ui/NhekoGlobalObject.h @@ -39,6 +39,7 @@ public: UserProfile *currentUser() const; Q_INVOKABLE void openLink(QString link) const; + Q_INVOKABLE void setStatusMessage(QString msg) const; public slots: void updateUserProfile(); -- cgit 1.5.1 From 53fcf7f428d8d7ef2390f5877fe8f682ba9971d3 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sun, 30 May 2021 12:41:44 +0200 Subject: Port remaining sidebar actions to qml --- resources/qml/RoomList.qml | 19 ++++ src/MainWindow.cpp | 1 - src/SideBarActions.cpp | 120 ------------------------ src/SideBarActions.h | 54 ----------- src/Splitter.cpp | 166 -------------------------------- src/Splitter.h | 49 ---------- src/UserInfoWidget.cpp | 219 ------------------------------------------- src/UserInfoWidget.h | 68 -------------- src/ui/NhekoGlobalObject.cpp | 27 ++++++ src/ui/NhekoGlobalObject.h | 4 + 10 files changed, 50 insertions(+), 677 deletions(-) delete mode 100644 src/SideBarActions.cpp delete mode 100644 src/SideBarActions.h delete mode 100644 src/Splitter.cpp delete mode 100644 src/Splitter.h delete mode 100644 src/UserInfoWidget.cpp delete mode 100644 src/UserInfoWidget.h (limited to 'src/ui/NhekoGlobalObject.cpp') diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index c5e07032..3109b75c 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -477,6 +477,7 @@ Page { image: ":/icons/icons/ui/power-button-off.png" ToolTip.visible: hovered ToolTip.text: qsTr("Logout") + onClicked: Nheko.openLogoutDialog() } } @@ -523,6 +524,23 @@ Page { ToolTip.visible: hovered ToolTip.text: qsTr("Start a new chat") Layout.margins: Nheko.paddingMedium + + onClicked: roomJoinCreateMenu.open(parent) + + Platform.Menu { + id: roomJoinCreateMenu + + Platform.MenuItem { + text: qsTr("Join a room") + onTriggered: Nheko.openJoinRoomDialog() + } + + Platform.MenuItem { + text: qsTr("Create a new room") + onTriggered: Nheko.openCreateRoomDialog() + } + + } } ImageButton { @@ -545,6 +563,7 @@ Page { ToolTip.visible: hovered ToolTip.text: qsTr("User settings") Layout.margins: Nheko.paddingMedium + onClicked: Nheko.showUserSettingsPage() } } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 057ee4af..ed337ca4 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -22,7 +22,6 @@ #include "MainWindow.h" #include "MatrixClient.h" #include "RegisterPage.h" -#include "Splitter.h" #include "TrayIcon.h" #include "UserSettingsPage.h" #include "Utils.h" diff --git a/src/SideBarActions.cpp b/src/SideBarActions.cpp deleted file mode 100644 index 0b7756f0..00000000 --- a/src/SideBarActions.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include -#include -#include -#include -#include - -#include - -#include "Config.h" -#include "MainWindow.h" -#include "SideBarActions.h" -#include "Splitter.h" -#include "ui/FlatButton.h" -#include "ui/Menu.h" - -SideBarActions::SideBarActions(QWidget *parent) - : QWidget{parent} -{ - QFont f; - f.setPointSizeF(f.pointSizeF()); - - const int fontHeight = QFontMetrics(f).height(); - const int contentHeight = fontHeight * 2.5; - - setFixedHeight(contentHeight); - - layout_ = new QHBoxLayout(this); - layout_->setMargin(0); - - QIcon settingsIcon; - settingsIcon.addFile(":/icons/icons/ui/settings.png"); - - QIcon createRoomIcon; - createRoomIcon.addFile(":/icons/icons/ui/add-square-button.png"); - - QIcon joinRoomIcon; - joinRoomIcon.addFile(":/icons/icons/ui/speech-bubbles-comment-option.png"); - - settingsBtn_ = new FlatButton(this); - settingsBtn_->setToolTip(tr("User settings")); - settingsBtn_->setIcon(settingsIcon); - settingsBtn_->setCornerRadius(conf::sidebarActions::iconSize / 2); - settingsBtn_->setIconSize( - QSize(conf::sidebarActions::iconSize, conf::sidebarActions::iconSize)); - - addMenu_ = new Menu(this); - createRoomAction_ = new QAction(tr("Create new room"), this); - joinRoomAction_ = new QAction(tr("Join a room"), this); - - connect(joinRoomAction_, &QAction::triggered, this, [this]() { - MainWindow::instance()->openJoinRoomDialog( - [this](const QString &room_id) { emit joinRoom(room_id); }); - }); - - connect(createRoomAction_, &QAction::triggered, this, [this]() { - MainWindow::instance()->openCreateRoomDialog( - [this](const mtx::requests::CreateRoom &req) { emit createRoom(req); }); - }); - - addMenu_->addAction(createRoomAction_); - addMenu_->addAction(joinRoomAction_); - - createRoomBtn_ = new FlatButton(this); - createRoomBtn_->setToolTip(tr("Start a new chat")); - createRoomBtn_->setIcon(createRoomIcon); - createRoomBtn_->setCornerRadius(conf::sidebarActions::iconSize / 2); - createRoomBtn_->setIconSize( - QSize(conf::sidebarActions::iconSize, conf::sidebarActions::iconSize)); - - connect(createRoomBtn_, &QPushButton::clicked, this, [this]() { - auto pos = mapToGlobal(createRoomBtn_->pos()); - auto padding = conf::sidebarActions::iconSize / 2; - - addMenu_->popup( - QPoint(pos.x() + padding, pos.y() - padding - addMenu_->sizeHint().height())); - }); - - roomDirectory_ = new FlatButton(this); - roomDirectory_->setToolTip(tr("Room directory")); - roomDirectory_->setEnabled(false); - roomDirectory_->setIcon(joinRoomIcon); - roomDirectory_->setCornerRadius(conf::sidebarActions::iconSize / 2); - roomDirectory_->setIconSize( - QSize(conf::sidebarActions::iconSize, conf::sidebarActions::iconSize)); - - layout_->addWidget(createRoomBtn_); - layout_->addWidget(roomDirectory_); - layout_->addWidget(settingsBtn_); - - connect(settingsBtn_, &QPushButton::clicked, this, &SideBarActions::showSettings); -} - -void -SideBarActions::resizeEvent(QResizeEvent *event) -{ - Q_UNUSED(event); - - const auto sidebarSizes = splitter::calculateSidebarSizes(QFont{}); - - if (width() <= sidebarSizes.small) { - roomDirectory_->hide(); - createRoomBtn_->hide(); - } else { - roomDirectory_->show(); - createRoomBtn_->show(); - } -} - -void -SideBarActions::paintEvent(QPaintEvent *) -{ - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/SideBarActions.h b/src/SideBarActions.h deleted file mode 100644 index 566aa76b..00000000 --- a/src/SideBarActions.h +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include -#include - -namespace mtx { -namespace requests { -struct CreateRoom; -} -} - -class Menu; -class FlatButton; -class QResizeEvent; - -class SideBarActions : public QWidget -{ - Q_OBJECT - - Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor) - -public: - SideBarActions(QWidget *parent = nullptr); - - QColor borderColor() const { return borderColor_; } - void setBorderColor(QColor &color) { borderColor_ = color; } - -signals: - void showSettings(); - void joinRoom(const QString &room); - void createRoom(const mtx::requests::CreateRoom &request); - -protected: - void resizeEvent(QResizeEvent *event) override; - void paintEvent(QPaintEvent *event) override; - -private: - QHBoxLayout *layout_; - - Menu *addMenu_; - QAction *createRoomAction_; - QAction *joinRoomAction_; - - FlatButton *settingsBtn_; - FlatButton *createRoomBtn_; - FlatButton *roomDirectory_; - - QColor borderColor_; -}; diff --git a/src/Splitter.cpp b/src/Splitter.cpp deleted file mode 100644 index 15e3f5c5..00000000 --- a/src/Splitter.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Konstantinos Sideris -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include - -#include "Logging.h" -#include "Splitter.h" - -constexpr auto MaxWidth = (1 << 24) - 1; - -Splitter::Splitter(QWidget *parent) - : QSplitter(parent) - , sz_{splitter::calculateSidebarSizes(QFont{})} -{ - connect(this, &QSplitter::splitterMoved, this, &Splitter::onSplitterMoved); - setChildrenCollapsible(false); -} - -void -Splitter::restoreSizes(int fallback) -{ - QSettings settings; - int savedWidth = settings.value("sidebar/width").toInt(); - - auto left = widget(0); - if (savedWidth <= 0) { - hideSidebar(); - return; - } else if (savedWidth <= sz_.small) { - if (left) { - left->setMinimumWidth(sz_.small); - left->setMaximumWidth(sz_.small); - return; - } - } else if (savedWidth < sz_.normal) { - savedWidth = sz_.normal; - } - - left->setMinimumWidth(sz_.normal); - left->setMaximumWidth(2 * sz_.normal); - setSizes({savedWidth, fallback - savedWidth}); - - setStretchFactor(0, 0); - setStretchFactor(1, 1); -} - -Splitter::~Splitter() -{ - auto left = widget(0); - - if (left) { - QSettings settings; - settings.setValue("sidebar/width", left->width()); - } -} - -void -Splitter::onSplitterMoved(int pos, int index) -{ - Q_UNUSED(pos); - Q_UNUSED(index); - - auto s = sizes(); - - if (s.count() < 2) { - nhlog::ui()->warn("Splitter needs at least two children"); - return; - } - - if (s[0] == sz_.normal) { - rightMoveCount_ += 1; - - if (rightMoveCount_ > moveEventLimit_) { - auto left = widget(0); - auto cursorPosition = left->mapFromGlobal(QCursor::pos()); - - // if we are coming from the right, the cursor should - // end up on the first widget. - if (left->rect().contains(cursorPosition)) { - left->setMinimumWidth(sz_.small); - left->setMaximumWidth(sz_.small); - - rightMoveCount_ = 0; - } - } - } else if (s[0] == sz_.small) { - leftMoveCount_ += 1; - - if (leftMoveCount_ > moveEventLimit_) { - auto left = widget(0); - auto right = widget(1); - auto cursorPosition = right->mapFromGlobal(QCursor::pos()); - - // We move the start a little further so the transition isn't so abrupt. - auto extended = right->rect(); - extended.translate(100, 0); - - // if we are coming from the left, the cursor should - // end up on the second widget. - if (extended.contains(cursorPosition) && - right->size().width() >= sz_.collapsePoint + sz_.normal) { - left->setMinimumWidth(sz_.normal); - left->setMaximumWidth(2 * sz_.normal); - - leftMoveCount_ = 0; - } - } - } -} - -void -Splitter::hideSidebar() -{ - auto left = widget(0); - if (left) - left->hide(); -} - -void -Splitter::showChatView() -{ - auto left = widget(0); - auto right = widget(1); - - if (right->isHidden()) { - left->hide(); - right->show(); - - // Restore previous size. - if (left->minimumWidth() == sz_.small) { - left->setMinimumWidth(sz_.small); - left->setMaximumWidth(sz_.small); - } else { - left->setMinimumWidth(sz_.normal); - left->setMaximumWidth(2 * sz_.normal); - } - } -} - -void -Splitter::showFullRoomList() -{ - auto left = widget(0); - auto right = widget(1); - - right->hide(); - - left->show(); - left->setMaximumWidth(MaxWidth); -} - -splitter::SideBarSizes -splitter::calculateSidebarSizes(const QFont &f) -{ - const auto height = static_cast(QFontMetrics{f}.lineSpacing()); - - SideBarSizes sz; - sz.small = std::ceil(3.8 * height); - sz.normal = std::ceil(16 * height); - sz.groups = std::ceil(3 * height); - sz.collapsePoint = 2 * sz.normal; - - return sz; -} diff --git a/src/Splitter.h b/src/Splitter.h deleted file mode 100644 index 94622f89..00000000 --- a/src/Splitter.h +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Konstantinos Sideris -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include - -namespace splitter { -struct SideBarSizes -{ - int small; - int normal; - int groups; - int collapsePoint; -}; - -SideBarSizes -calculateSidebarSizes(const QFont &f); -} - -class Splitter : public QSplitter -{ - Q_OBJECT -public: - explicit Splitter(QWidget *parent = nullptr); - ~Splitter() override; - - void restoreSizes(int fallback); - -public slots: - void hideSidebar(); - void showFullRoomList(); - void showChatView(); - -signals: - void hiddenSidebar(); - -private: - void onSplitterMoved(int pos, int index); - - int moveEventLimit_ = 50; - - int leftMoveCount_ = 0; - int rightMoveCount_ = 0; - - splitter::SideBarSizes sz_; -}; diff --git a/src/UserInfoWidget.cpp b/src/UserInfoWidget.cpp deleted file mode 100644 index 3d526b8b..00000000 --- a/src/UserInfoWidget.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Konstantinos Sideris -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "ChatPage.h" -#include "Config.h" -#include "MainWindow.h" -#include "Splitter.h" -#include "UserInfoWidget.h" -#include "UserSettingsPage.h" -#include "ui/Avatar.h" -#include "ui/FlatButton.h" -#include "ui/OverlayModal.h" - -UserInfoWidget::UserInfoWidget(QWidget *parent) - : QWidget(parent) - , display_name_("User") - , user_id_("@user:homeserver.org") -{ - QFont f; - f.setPointSizeF(f.pointSizeF()); - - const int fontHeight = QFontMetrics(f).height(); - const int widgetMargin = fontHeight / 3; - const int contentHeight = fontHeight * 3; - - logoutButtonSize_ = std::min(fontHeight, 20); - - setFixedHeight(contentHeight + widgetMargin); - - topLayout_ = new QHBoxLayout(this); - topLayout_->setSpacing(0); - topLayout_->setMargin(widgetMargin); - - avatarLayout_ = new QHBoxLayout(); - textLayout_ = new QVBoxLayout(); - textLayout_->setSpacing(widgetMargin / 2); - textLayout_->setContentsMargins(widgetMargin * 2, widgetMargin, widgetMargin, widgetMargin); - - userAvatar_ = new Avatar(this, fontHeight * 2.5); - userAvatar_->setObjectName("userAvatar"); - userAvatar_->setLetter(QChar('?')); - - QFont nameFont; - nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1); - nameFont.setWeight(QFont::Medium); - - displayNameLabel_ = new QLabel(this); - displayNameLabel_->setFont(nameFont); - displayNameLabel_->setObjectName("displayNameLabel"); - displayNameLabel_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - - userIdLabel_ = new QLabel(this); - userIdLabel_->setFont(f); - userIdLabel_->setObjectName("userIdLabel"); - userIdLabel_->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - - avatarLayout_->addWidget(userAvatar_); - textLayout_->addWidget(displayNameLabel_, 0, Qt::AlignBottom); - textLayout_->addWidget(userIdLabel_, 0, Qt::AlignTop); - - topLayout_->addLayout(avatarLayout_); - topLayout_->addLayout(textLayout_); - topLayout_->addStretch(1); - - buttonLayout_ = new QHBoxLayout(); - buttonLayout_->setSpacing(0); - buttonLayout_->setMargin(0); - - logoutButton_ = new FlatButton(this); - logoutButton_->setToolTip(tr("Logout")); - logoutButton_->setCornerRadius(logoutButtonSize_ / 2); - - QIcon icon; - icon.addFile(":/icons/icons/ui/power-button-off.png"); - - logoutButton_->setIcon(icon); - logoutButton_->setIconSize(QSize(logoutButtonSize_, logoutButtonSize_)); - - buttonLayout_->addWidget(logoutButton_); - - topLayout_->addLayout(buttonLayout_); - - // Show the confirmation dialog. - connect(logoutButton_, &QPushButton::clicked, this, []() { - MainWindow::instance()->openLogoutDialog(); - }); - - menu = new QMenu(this); - - auto setStatusAction = menu->addAction(tr("Set custom status message")); - connect(setStatusAction, &QAction::triggered, this, [this]() { - bool ok = false; - QString text = QInputDialog::getText(this, - tr("Custom status message"), - tr("Status:"), - QLineEdit::Normal, - ChatPage::instance()->status(), - &ok); - if (ok) - ChatPage::instance()->setStatus(text); - }); - - auto userProfileAction = menu->addAction(tr("User Profile Settings")); - connect( - userProfileAction, &QAction::triggered, this, [this]() { emit openGlobalUserProfile(); }); - -#if 0 // disable presence menu until issues in synapse are resolved - auto setAutoPresence = menu->addAction(tr("Set presence automatically")); - connect(setAutoPresence, &QAction::triggered, this, []() { - ChatPage::instance()->userSettings()->setPresence( - UserSettings::Presence::AutomaticPresence); - ChatPage::instance()->setStatus(ChatPage::instance()->status()); - }); - auto setOnline = menu->addAction(tr("Online")); - connect(setOnline, &QAction::triggered, this, []() { - ChatPage::instance()->userSettings()->setPresence(UserSettings::Presence::Online); - ChatPage::instance()->setStatus(ChatPage::instance()->status()); - }); - auto setUnavailable = menu->addAction(tr("Unavailable")); - connect(setUnavailable, &QAction::triggered, this, []() { - ChatPage::instance()->userSettings()->setPresence( - UserSettings::Presence::Unavailable); - ChatPage::instance()->setStatus(ChatPage::instance()->status()); - }); - auto setOffline = menu->addAction(tr("Offline")); - connect(setOffline, &QAction::triggered, this, []() { - ChatPage::instance()->userSettings()->setPresence(UserSettings::Presence::Offline); - ChatPage::instance()->setStatus(ChatPage::instance()->status()); - }); -#endif -} - -void -UserInfoWidget::contextMenuEvent(QContextMenuEvent *event) -{ - menu->popup(event->globalPos()); -} - -void -UserInfoWidget::resizeEvent(QResizeEvent *event) -{ - Q_UNUSED(event); - - const auto sz = splitter::calculateSidebarSizes(QFont{}); - - if (width() <= sz.small) { - topLayout_->setContentsMargins(0, 0, logoutButtonSize_, 0); - - userAvatar_->hide(); - displayNameLabel_->hide(); - userIdLabel_->hide(); - } else { - topLayout_->setMargin(5); - userAvatar_->show(); - displayNameLabel_->show(); - userIdLabel_->show(); - } - - QWidget::resizeEvent(event); -} - -void -UserInfoWidget::reset() -{ - displayNameLabel_->setText(""); - userIdLabel_->setText(""); - userAvatar_->setLetter(QChar('?')); -} - -void -UserInfoWidget::setDisplayName(const QString &name) -{ - if (name.isEmpty()) - display_name_ = user_id_.split(':')[0].split('@')[1]; - else - display_name_ = name; - - displayNameLabel_->setText(display_name_); - userAvatar_->setLetter(QChar(display_name_[0])); - update(); -} - -void -UserInfoWidget::setUserId(const QString &userid) -{ - user_id_ = userid; - userIdLabel_->setText(userid); - update(); -} - -void -UserInfoWidget::setAvatar(const QString &url) -{ - userAvatar_->setImage(url); - update(); -} - -void -UserInfoWidget::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); - - QStyleOption opt; - opt.init(this); - QPainter p(this); - style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); -} diff --git a/src/UserInfoWidget.h b/src/UserInfoWidget.h deleted file mode 100644 index 5aec1cda..00000000 --- a/src/UserInfoWidget.h +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-FileCopyrightText: 2017 Konstantinos Sideris -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include - -class Avatar; -class FlatButton; -class OverlayModal; - -class QLabel; -class QHBoxLayout; -class QVBoxLayout; -class QMenu; - -class UserInfoWidget : public QWidget -{ - Q_OBJECT - - Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor) - -public: - UserInfoWidget(QWidget *parent = nullptr); - - void setDisplayName(const QString &name); - void setUserId(const QString &userid); - void setAvatar(const QString &url); - - void reset(); - - QColor borderColor() const { return borderColor_; } - void setBorderColor(QColor &color) { borderColor_ = color; } - -protected: - void resizeEvent(QResizeEvent *event) override; - void paintEvent(QPaintEvent *event) override; - void contextMenuEvent(QContextMenuEvent *) override; - -signals: - void openGlobalUserProfile(); - -private: - Avatar *userAvatar_; - - QHBoxLayout *topLayout_; - QHBoxLayout *avatarLayout_; - QVBoxLayout *textLayout_; - QHBoxLayout *buttonLayout_; - - FlatButton *logoutButton_; - - QLabel *displayNameLabel_; - QLabel *userIdLabel_; - - QString display_name_; - QString user_id_; - - QImage avatar_image_; - - int logoutButtonSize_; - - QColor borderColor_; - - QMenu *menu = nullptr; -}; diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp index fd572b4b..fea10839 100644 --- a/src/ui/NhekoGlobalObject.cpp +++ b/src/ui/NhekoGlobalObject.cpp @@ -10,6 +10,7 @@ #include "Cache_p.h" #include "ChatPage.h" #include "Logging.h" +#include "MainWindow.h" #include "UserSettingsPage.h" #include "Utils.h" @@ -113,3 +114,29 @@ Nheko::currentUser() const return currentUser_.get(); } + +void +Nheko::showUserSettingsPage() const +{ + ChatPage::instance()->showUserSettingsPage(); +} + +void +Nheko::openLogoutDialog() const +{ + MainWindow::instance()->openLogoutDialog(); +} + +void +Nheko::openCreateRoomDialog() const +{ + MainWindow::instance()->openCreateRoomDialog( + [](const mtx::requests::CreateRoom &req) { ChatPage::instance()->createRoom(req); }); +} + +void +Nheko::openJoinRoomDialog() const +{ + MainWindow::instance()->openJoinRoomDialog( + [](const QString &room_id) { ChatPage::instance()->joinRoom(room_id); }); +} diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h index 593514fa..14135fd1 100644 --- a/src/ui/NhekoGlobalObject.h +++ b/src/ui/NhekoGlobalObject.h @@ -40,6 +40,10 @@ public: Q_INVOKABLE void openLink(QString link) const; Q_INVOKABLE void setStatusMessage(QString msg) const; + Q_INVOKABLE void showUserSettingsPage() const; + Q_INVOKABLE void openLogoutDialog() const; + Q_INVOKABLE void openCreateRoomDialog() const; + Q_INVOKABLE void openJoinRoomDialog() const; public slots: void updateUserProfile(); -- cgit 1.5.1