diff --git a/src/ui/NhekoDropArea.cpp b/src/ui/NhekoDropArea.cpp
index 54f48d3c..bbcedd7e 100644
--- a/src/ui/NhekoDropArea.cpp
+++ b/src/ui/NhekoDropArea.cpp
@@ -35,7 +35,7 @@ void
NhekoDropArea::dropEvent(QDropEvent *event)
{
if (event) {
- auto model = ChatPage::instance()->timelineManager()->getHistoryView(roomid_);
+ auto model = ChatPage::instance()->timelineManager()->rooms()->getRoomById(roomid_);
if (model) {
model->input()->insertMimeData(event->mimeData());
}
diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp
new file mode 100644
index 00000000..fea10839
--- /dev/null
+++ b/src/ui/NhekoGlobalObject.cpp
@@ -0,0 +1,142 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "NhekoGlobalObject.h"
+
+#include <QDesktopServices>
+#include <QUrl>
+
+#include "Cache_p.h"
+#include "ChatPage.h"
+#include "Logging.h"
+#include "MainWindow.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 Theme::paletteFromTheme(UserSettings::instance()->theme().toStdString());
+}
+
+QPalette
+Nheko::inactiveColors() const
+{
+ 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
+{
+ 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
+Nheko::setStatusMessage(QString msg) const
+{
+ ChatPage::instance()->setStatus(msg);
+}
+
+UserProfile *
+Nheko::currentUser() const
+{
+ nhlog::ui()->debug("Profile requested");
+
+ 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
new file mode 100644
index 00000000..14135fd1
--- /dev/null
+++ b/src/ui/NhekoGlobalObject.h
@@ -0,0 +1,57 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <QObject>
+#include <QPalette>
+
+#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;
+ 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();
+
+signals:
+ void colorsChanged();
+ void profileChanged();
+
+private:
+ QScopedPointer<UserProfile> currentUser_;
+};
diff --git a/src/ui/Theme.cpp b/src/ui/Theme.cpp
index 4341bd63..26119393 100644
--- a/src/ui/Theme.cpp
+++ b/src/ui/Theme.cpp
@@ -2,76 +2,73 @@
//
// SPDX-License-Identifier: GPL-3.0-or-later
-#include <QDebug>
-
#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>("Theme");
+ static QPalette original;
+ if (theme == "light") {
+ QPalette lightActive(
+ /*windowText*/ QColor("#333"),
+ /*button*/ QColor("white"),
+ /*light*/ QColor(0xef, 0xef, 0xef),
+ /*dark*/ QColor(70, 77, 93),
+ /*mid*/ QColor(220, 220, 220),
+ /*text*/ QColor("#333"),
+ /*bright_text*/ QColor("#f2f5f8"),
+ /*base*/ QColor("#fff"),
+ /*window*/ QColor("white"));
+ lightActive.setColor(QPalette::AlternateBase, QColor("#eee"));
+ lightActive.setColor(QPalette::Highlight, QColor("#38a3d8"));
+ lightActive.setColor(QPalette::HighlightedText, QColor("#f4f4f5"));
+ 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(60, 70, 77),
+ /*mid*/ QColor("#202228"),
+ /*text*/ QColor("#caccd1"),
+ /*bright_text*/ QColor("#f4f5f8"),
+ /*base*/ QColor("#202228"),
+ /*window*/ QColor("#2d3139"));
+ darkActive.setColor(QPalette::AlternateBase, QColor("#2d3139"));
+ darkActive.setColor(QPalette::Highlight, QColor("#38a3d8"));
+ darkActive.setColor(QPalette::HighlightedText, QColor("#f4f5f8"));
+ 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<int>(color)]);
+ auto p = paletteFromTheme(theme);
+ separator_ = p.mid().color();
+ if (theme == "light") {
+ sidebarBackground_ = QColor("#233649");
+ alternateButton_ = QColor("#ccc");
+ red_ = QColor("#a82353");
+ } else if (theme == "dark") {
+ sidebarBackground_ = QColor("#2d3139");
+ alternateButton_ = QColor("#414A59");
+ red_ = QColor("#a82353");
+ } else {
+ sidebarBackground_ = p.window().color();
+ alternateButton_ = p.dark().color();
+ red_ = QColor("red");
+ }
}
diff --git a/src/ui/Theme.h b/src/ui/Theme.h
index 3243c076..b5bcd4dd 100644
--- a/src/ui/Theme.h
+++ b/src/ui/Theme.h
@@ -5,8 +5,7 @@
#pragma once
#include <QColor>
-#include <QHash>
-#include <QObject>
+#include <QPalette>
namespace ui {
enum class AvatarType
@@ -60,36 +59,25 @@ 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 alternateButton READ alternateButton CONSTANT)
+ Q_PROPERTY(QColor separator READ separator CONSTANT)
+ Q_PROPERTY(QColor red READ red 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 alternateButton() const { return alternateButton_; }
+ QColor separator() const { return separator_; }
+ QColor red() const { return red_; }
private:
- QColor rgba(int r, int g, int b, qreal a) const;
-
- QHash<QString, QColor> colors_;
+ QColor sidebarBackground_, separator_, red_, alternateButton_;
};
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 <QCommonStyle>
-#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..3d9c4b6a 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() ||
+ !ChatPage::instance()->timelineManager())
+ return;
+
connect(cache::client(),
&Cache::verificationStatusChanged,
this,
@@ -53,17 +66,9 @@ UserProfile::UserProfile(QString roomid,
: verification::VERIFIED;
}
deviceList_.reset(deviceList_.deviceList_);
+ emit devicesChanged();
});
-
- connect(this,
- &UserProfile::globalUsernameRetrieved,
- this,
- &UserProfile::setGlobalUsername,
- Qt::QueuedConnection);
-
- if (isGlobalUserProfile()) {
- getGlobalProfileData();
- }
+ fetchDeviceList(this->userid_);
}
QHash<int, QByteArray>
@@ -123,10 +128,7 @@ UserProfile::displayName()
QString
UserProfile::avatarUrl()
{
- return (isGlobalUserProfile() && globalAvatarUrl != "")
- ? globalAvatarUrl
- : cache::avatarUrl(roomid_, userid_);
- ;
+ return isGlobalUserProfile() ? globalAvatarUrl : cache::avatarUrl(roomid_, userid_);
}
bool
@@ -157,6 +159,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,
@@ -217,6 +222,7 @@ UserProfile::fetchDeviceList(const QString &userID)
}
this->deviceList_.queueReset(std::move(deviceInfo));
+ emit devicesChanged();
});
});
}
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index bf71d0de..721d7230 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -90,7 +90,7 @@ class UserProfile : public QObject
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
Q_PROPERTY(QString userid READ userid CONSTANT)
Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged)
- Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList CONSTANT)
+ Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList NOTIFY devicesChanged)
Q_PROPERTY(bool isGlobalUserProfile READ isGlobalUserProfile CONSTANT)
Q_PROPERTY(int userVerified READ getUserStatus NOTIFY userStatusChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
@@ -133,6 +133,7 @@ signals:
void avatarUrlChanged();
void displayError(const QString &errorMessage);
void globalUsernameRetrieved(const QString &globalUser);
+ void devicesChanged();
public slots:
void updateAvatarUrl();
|