summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJoseph Donofry <joedonofry@gmail.com>2020-06-09 20:51:36 -0400
committerJoseph Donofry <joedonofry@gmail.com>2020-06-09 20:51:36 -0400
commit6bb73f84a3075abe7a1c1fd2d56a259740070c70 (patch)
treeeecb0bc3ec18a04cd226d1caea74b2b65ef6d851 /src
parentMinor adjustments to emoji picker (diff)
parentSmooth scaling for images (diff)
downloadnheko-6bb73f84a3075abe7a1c1fd2d56a259740070c70.tar.xz
Merge master and fix conflicts
Diffstat (limited to 'src')
-rw-r--r--src/Cache.cpp14
-rw-r--r--src/ChatPage.cpp14
-rw-r--r--src/CommunitiesListItem.h1
-rw-r--r--src/EventAccessors.cpp6
-rw-r--r--src/EventAccessors.h3
-rw-r--r--src/InviteeItem.cpp1
-rw-r--r--src/InviteeItem.h2
-rw-r--r--src/LoginPage.cpp11
-rw-r--r--src/LoginPage.h7
-rw-r--r--src/MainWindow.cpp4
-rw-r--r--src/MxcImageProvider.cpp3
-rw-r--r--src/RegisterPage.cpp9
-rw-r--r--src/RegisterPage.h7
-rw-r--r--src/RoomInfoListItem.cpp2
-rw-r--r--src/RoomList.cpp2
-rw-r--r--src/SideBarActions.cpp2
-rw-r--r--src/TopRoomBar.h1
-rw-r--r--src/UserInfoWidget.cpp3
-rw-r--r--src/UserInfoWidget.h7
-rw-r--r--src/UserSettingsPage.cpp417
-rw-r--r--src/UserSettingsPage.h193
-rw-r--r--src/Utils.cpp16
-rw-r--r--src/Utils.h39
-rw-r--r--src/dialogs/CreateRoom.cpp4
-rw-r--r--src/dialogs/InviteUsers.cpp1
-rw-r--r--src/dialogs/InviteUsers.h4
-rw-r--r--src/dialogs/ReadReceipts.cpp18
-rw-r--r--src/dialogs/ReadReceipts.h14
-rw-r--r--src/dialogs/RoomSettings.cpp34
-rw-r--r--src/dialogs/RoomSettings.h35
-rw-r--r--src/emoji/Category.cpp3
-rw-r--r--src/emoji/Category.h9
-rw-r--r--src/popups/PopupItem.cpp1
-rw-r--r--src/popups/PopupItem.h5
-rw-r--r--src/popups/SuggestionsPopup.h3
-rw-r--r--src/popups/UserMentions.cpp11
-rw-r--r--src/timeline/TimelineModel.cpp24
-rw-r--r--src/timeline/TimelineModel.h1
-rw-r--r--src/timeline/TimelineViewManager.cpp13
-rw-r--r--src/ui/Avatar.cpp1
-rw-r--r--src/ui/InfoMessage.cpp1
-rw-r--r--src/ui/Painter.h3
42 files changed, 611 insertions, 338 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp

index 1061e60e..009cbabc 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp
@@ -31,6 +31,7 @@ #include "Cache.h" #include "Cache_p.h" +#include "EventAccessors.h" #include "Logging.h" #include "Utils.h" @@ -1947,13 +1948,14 @@ Cache::saveTimelineMessages(lmdb::txn &txn, json obj = json::object(); - obj["event"] = utils::serialize_event(e); + obj["event"] = mtx::accessors::serialize_event(e); obj["token"] = res.prev_batch; - lmdb::dbi_put(txn, - db, - lmdb::val(std::to_string(utils::event_timestamp(e))), - lmdb::val(obj.dump())); + lmdb::dbi_put( + txn, + db, + lmdb::val(std::to_string(obj["event"]["origin_server_ts"].get<uint64_t>())), + lmdb::val(obj.dump())); } } @@ -2026,7 +2028,7 @@ Cache::saveTimelineMentions(lmdb::txn &txn, using namespace mtx::events::state; for (const auto &notif : res) { - const auto event_id = utils::event_id(notif.event); + const auto event_id = mtx::accessors::event_id(notif.event); // double check that we have the correct room_id... if (room_id.compare(notif.room_id) != 0) { diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 1e06da5d..2340b146 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp
@@ -26,6 +26,7 @@ #include "Cache.h" #include "Cache_p.h" #include "ChatPage.h" +#include "EventAccessors.h" #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" @@ -255,7 +256,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) text_input_, &TextInputWidget::startedTyping, this, &ChatPage::sendTypingNotifications); connect(typingRefresher_, &QTimer::timeout, this, &ChatPage::sendTypingNotifications); connect(text_input_, &TextInputWidget::stoppedTyping, this, [this]() { - if (!userSettings_->isTypingNotificationsEnabled()) + if (!userSettings_->typingNotifications()) return; typingRefresher_->stop(); @@ -482,7 +483,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) activateWindow(); }); - setGroupViewState(userSettings_->isGroupViewEnabled()); + setGroupViewState(userSettings_->groupView()); connect(userSettings_.data(), &UserSettings::groupViewStateChanged, @@ -891,7 +892,7 @@ void ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res) { for (const auto &item : res.notifications) { - const auto event_id = utils::event_id(item.event); + const auto event_id = mtx::accessors::event_id(item.event); try { if (item.read) { @@ -901,7 +902,8 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res) if (!cache::isNotificationSent(event_id)) { const auto room_id = QString::fromStdString(item.room_id); - const auto user_id = utils::event_sender(item.event); + const auto user_id = + QString::fromStdString(mtx::accessors::sender(item.event)); // We should only sent one notification per event. cache::markSentNotification(event_id); @@ -1213,7 +1215,7 @@ ChatPage::unbanUser(QString userid, QString reason) void ChatPage::sendTypingNotifications() { - if (!userSettings_->isTypingNotificationsEnabled()) + if (!userSettings_->typingNotifications()) return; http::client()->start_typing( @@ -1349,7 +1351,7 @@ ChatPage::hideSideBars() void ChatPage::showSideBars() { - if (userSettings_->isGroupViewEnabled()) + if (userSettings_->groupView()) communitiesList_->show(); sideBar_->show(); diff --git a/src/CommunitiesListItem.h b/src/CommunitiesListItem.h
index 0cc5d60c..535a6ec0 100644 --- a/src/CommunitiesListItem.h +++ b/src/CommunitiesListItem.h
@@ -7,7 +7,6 @@ #include "ui/Theme.h" class RippleOverlay; -class QPainter; class QMouseEvent; class CommunitiesListItem : public QWidget diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp
index 7f28eb46..a2d8adbb 100644 --- a/src/EventAccessors.cpp +++ b/src/EventAccessors.cpp
@@ -400,3 +400,9 @@ mtx::accessors::media_width(const mtx::events::collections::TimelineEvents &even { return std::visit(EventMediaWidth{}, event); } + +nlohmann::json +mtx::accessors::serialize_event(const mtx::events::collections::TimelineEvents &event) +{ + return std::visit([](const auto &e) { return nlohmann::json(e); }, event); +} diff --git a/src/EventAccessors.h b/src/EventAccessors.h
index c9ac4d00..a7577d86 100644 --- a/src/EventAccessors.h +++ b/src/EventAccessors.h
@@ -63,4 +63,7 @@ media_height(const mtx::events::collections::TimelineEvents &event); uint64_t media_width(const mtx::events::collections::TimelineEvents &event); + +nlohmann::json +serialize_event(const mtx::events::collections::TimelineEvents &event); } diff --git a/src/InviteeItem.cpp b/src/InviteeItem.cpp
index 906a3bfe..a6b471dc 100644 --- a/src/InviteeItem.cpp +++ b/src/InviteeItem.cpp
@@ -1,4 +1,5 @@ #include <QHBoxLayout> +#include <QLabel> #include <QPushButton> #include "InviteeItem.h" diff --git a/src/InviteeItem.h b/src/InviteeItem.h
index 582904b4..54c61938 100644 --- a/src/InviteeItem.h +++ b/src/InviteeItem.h
@@ -1,11 +1,11 @@ #pragma once -#include <QLabel> #include <QWidget> #include <mtx/identifiers.hpp> class QPushButton; +class QLabel; class InviteeItem : public QWidget { diff --git a/src/LoginPage.cpp b/src/LoginPage.cpp
index bb329699..9a920d1d 100644 --- a/src/LoginPage.cpp +++ b/src/LoginPage.cpp
@@ -16,6 +16,7 @@ */ #include <QDesktopServices> +#include <QLabel> #include <QPainter> #include <QStyleOption> @@ -118,7 +119,7 @@ LoginPage::LoginPage(QWidget *parent) deviceName_->setLabel(tr("Device name")); deviceName_->setToolTip( tr("A name for this device, which will be shown to others, when verifying your devices. " - "If none is provided, a random string is used for privacy purposes.")); + "If none is provided a default is used.")); serverInput_ = new TextField(this); serverInput_->setLabel("Homeserver address"); @@ -132,7 +133,7 @@ LoginPage::LoginPage(QWidget *parent) form_layout_->addLayout(matrixidLayout_); form_layout_->addWidget(password_input_); - form_layout_->addWidget(deviceName_, Qt::AlignHCenter, nullptr); + form_layout_->addWidget(deviceName_, Qt::AlignHCenter); form_layout_->addLayout(serverLayout_); button_layout_ = new QHBoxLayout(); @@ -180,6 +181,12 @@ LoginPage::LoginPage(QWidget *parent) } void +LoginPage::loginError(const QString &msg) +{ + error_label_->setText(msg); +} + +void LoginPage::onMatrixIdEntered() { error_label_->setText(""); diff --git a/src/LoginPage.h b/src/LoginPage.h
index 8a402aea..c9220297 100644 --- a/src/LoginPage.h +++ b/src/LoginPage.h
@@ -17,8 +17,6 @@ #pragma once -#include <QLabel> -#include <QLayout> #include <QWidget> class FlatButton; @@ -26,6 +24,9 @@ class LoadingIndicator; class OverlayModal; class RaisedButton; class TextField; +class QLabel; +class QVBoxLayout; +class QHBoxLayout; namespace mtx { namespace responses { @@ -65,7 +66,7 @@ protected: public slots: // Displays errors produced during the login. - void loginError(const QString &msg) { error_label_->setText(msg); } + void loginError(const QString &msg); private slots: // Callback for the back button. diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index c6abdca2..cc1d868b 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp
@@ -148,7 +148,7 @@ MainWindow::MainWindow(QWidget *parent) QSettings settings; - trayIcon_->setVisible(userSettings_->isTrayEnabled()); + trayIcon_->setVisible(userSettings_->tray()); if (hasActiveUser()) { QString token = settings.value("auth/access_token").toString(); @@ -286,7 +286,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { if (!qApp->isSavingSession() && isVisible() && pageSupportsTray() && - userSettings_->isTrayEnabled()) { + userSettings_->tray()) { event->ignore(); hide(); } diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp
index 8e67375d..a197e4aa 100644 --- a/src/MxcImageProvider.cpp +++ b/src/MxcImageProvider.cpp
@@ -17,7 +17,8 @@ MxcImageResponse::run() auto data = cache::image(fileName); if (!data.isNull()) { m_image = utils::readImage(&data); - m_image = m_image.scaled(m_requestedSize, Qt::KeepAspectRatio); + m_image = m_image.scaled( + m_requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); m_image.setText("mxc url", "mxc://" + m_id); if (!m_image.isNull()) { diff --git a/src/RegisterPage.cpp b/src/RegisterPage.cpp
index 03e9ab34..b8fe93b5 100644 --- a/src/RegisterPage.cpp +++ b/src/RegisterPage.cpp
@@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <QLabel> #include <QMetaType> #include <QPainter> #include <QStyleOption> @@ -106,10 +107,10 @@ RegisterPage::RegisterPage(QWidget *parent) tr("A server that allows registration. Since matrix is decentralized, you need to first " "find a server you can register on or host your own.")); - form_layout_->addWidget(username_input_, Qt::AlignHCenter, nullptr); - form_layout_->addWidget(password_input_, Qt::AlignHCenter, nullptr); - form_layout_->addWidget(password_confirmation_, Qt::AlignHCenter, nullptr); - form_layout_->addWidget(server_input_, Qt::AlignHCenter, nullptr); + form_layout_->addWidget(username_input_, Qt::AlignHCenter); + form_layout_->addWidget(password_input_, Qt::AlignHCenter); + form_layout_->addWidget(password_confirmation_, Qt::AlignHCenter); + form_layout_->addWidget(server_input_, Qt::AlignHCenter); button_layout_ = new QHBoxLayout(); button_layout_->setSpacing(0); diff --git a/src/RegisterPage.h b/src/RegisterPage.h
index ebc24bb1..59ba3d1d 100644 --- a/src/RegisterPage.h +++ b/src/RegisterPage.h
@@ -17,8 +17,8 @@ #pragma once -#include <QLabel> -#include <QLayout> +#include <QWidget> + #include <memory> #include <mtx/user_interactive.hpp> @@ -26,6 +26,9 @@ class FlatButton; class RaisedButton; class TextField; +class QLabel; +class QVBoxLayout; +class QHBoxLayout; class RegisterPage : public QWidget { diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp
index ad774360..f234b59b 100644 --- a/src/RoomInfoListItem.cpp +++ b/src/RoomInfoListItem.cpp
@@ -451,7 +451,7 @@ RoomInfoListItem::calculateImportance() const // returns ImportanceDisabled or Invite if (isInvite()) { return Invite; - } else if (!settings->isSortByImportanceEnabled()) { + } else if (!settings->sortByImportance()) { return ImportanceDisabled; } else if (unreadHighlightedMsgCount_) { return NewMentions; diff --git a/src/RoomList.cpp b/src/RoomList.cpp
index 85a22026..b4c507b5 100644 --- a/src/RoomList.cpp +++ b/src/RoomList.cpp
@@ -21,6 +21,8 @@ #include <QObject> #include <QPainter> #include <QScroller> +#include <QStyle> +#include <QStyleOption> #include <QTimer> #include "Logging.h" diff --git a/src/SideBarActions.cpp b/src/SideBarActions.cpp
index 4934ec05..5af01cc2 100644 --- a/src/SideBarActions.cpp +++ b/src/SideBarActions.cpp
@@ -1,6 +1,8 @@ #include <QIcon> #include <QPainter> #include <QResizeEvent> +#include <QStyle> +#include <QStyleOption> #include <mtx/requests.hpp> diff --git a/src/TopRoomBar.h b/src/TopRoomBar.h
index 1aa5934b..0c33c1e0 100644 --- a/src/TopRoomBar.h +++ b/src/TopRoomBar.h
@@ -27,7 +27,6 @@ class Menu; class TextLabel; class OverlayModal; -class QPainter; class QLabel; class QHBoxLayout; class QVBoxLayout; diff --git a/src/UserInfoWidget.cpp b/src/UserInfoWidget.cpp
index 2e21d41f..e11aa6aa 100644 --- a/src/UserInfoWidget.cpp +++ b/src/UserInfoWidget.cpp
@@ -16,7 +16,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <QLabel> #include <QPainter> +#include <QStyle> +#include <QStyleOption> #include <QTimer> #include <iostream> diff --git a/src/UserInfoWidget.h b/src/UserInfoWidget.h
index e1a925a4..575ade52 100644 --- a/src/UserInfoWidget.h +++ b/src/UserInfoWidget.h
@@ -17,13 +17,16 @@ #pragma once -#include <QLabel> -#include <QLayout> +#include <QWidget> class Avatar; class FlatButton; class OverlayModal; +class QLabel; +class QHBoxLayout; +class QVBoxLayout; + class UserInfoWidget : public QWidget { Q_OBJECT diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 6af08e12..dfd99069 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp
@@ -30,6 +30,7 @@ #include <QScrollArea> #include <QScroller> #include <QSettings> +#include <QSpinBox> #include <QStandardPaths> #include <QString> #include <QTextStream> @@ -51,54 +52,206 @@ void UserSettings::load() { QSettings settings; - isTrayEnabled_ = settings.value("user/window/tray", false).toBool(); - hasDesktopNotifications_ = settings.value("user/desktop_notifications", true).toBool(); - isStartInTrayEnabled_ = settings.value("user/window/start_in_tray", false).toBool(); - isGroupViewEnabled_ = settings.value("user/group_view", true).toBool(); - isButtonsInTimelineEnabled_ = settings.value("user/timeline/buttons", true).toBool(); - isMessageHoverHighlightEnabled_ = + tray_ = settings.value("user/window/tray", false).toBool(); + hasDesktopNotifications_ = settings.value("user/desktop_notifications", true).toBool(); + startInTray_ = settings.value("user/window/start_in_tray", false).toBool(); + groupView_ = settings.value("user/group_view", true).toBool(); + buttonsInTimeline_ = settings.value("user/timeline/buttons", true).toBool(); + timelineMaxWidth_ = settings.value("user/timeline/max_width", 0).toInt(); + messageHoverHighlight_ = settings.value("user/timeline/message_hover_highlight", false).toBool(); - isMarkdownEnabled_ = settings.value("user/markdown_enabled", true).toBool(); - isTypingNotificationsEnabled_ = settings.value("user/typing_notifications", true).toBool(); - sortByImportance_ = settings.value("user/sort_by_unread", true).toBool(); - isReadReceiptsEnabled_ = settings.value("user/read_receipts", true).toBool(); - theme_ = settings.value("user/theme", defaultTheme_).toString(); - font_ = settings.value("user/font_family", "default").toString(); - avatarCircles_ = settings.value("user/avatar_circles", true).toBool(); - decryptSidebar_ = settings.value("user/decrypt_sidebar", true).toBool(); - emojiFont_ = settings.value("user/emoji_font_family", "default").toString(); - baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble(); + enlargeEmojiOnlyMessages_ = + settings.value("user/timeline/enlarge_emoji_only_msg", false).toBool(); + markdown_ = settings.value("user/markdown_enabled", true).toBool(); + typingNotifications_ = settings.value("user/typing_notifications", true).toBool(); + sortByImportance_ = settings.value("user/sort_by_unread", true).toBool(); + readReceipts_ = settings.value("user/read_receipts", true).toBool(); + theme_ = settings.value("user/theme", defaultTheme_).toString(); + font_ = settings.value("user/font_family", "default").toString(); + avatarCircles_ = settings.value("user/avatar_circles", true).toBool(); + decryptSidebar_ = settings.value("user/decrypt_sidebar", true).toBool(); + emojiFont_ = settings.value("user/emoji_font_family", "default").toString(); + baseFontSize_ = settings.value("user/font_size", QFont().pointSizeF()).toDouble(); applyTheme(); } +void +UserSettings::setMessageHoverHighlight(bool state) +{ + if (state == messageHoverHighlight_) + return; + messageHoverHighlight_ = state; + emit messageHoverHighlightChanged(state); + save(); +} +void +UserSettings::setEnlargeEmojiOnlyMessages(bool state) +{ + if (state == enlargeEmojiOnlyMessages_) + return; + enlargeEmojiOnlyMessages_ = state; + emit enlargeEmojiOnlyMessagesChanged(state); + save(); +} +void +UserSettings::setTray(bool state) +{ + if (state == tray_) + return; + tray_ = state; + emit trayChanged(state); + save(); +} + +void +UserSettings::setStartInTray(bool state) +{ + if (state == startInTray_) + return; + startInTray_ = state; + emit startInTrayChanged(state); + save(); +} + +void +UserSettings::setGroupView(bool state) +{ + if (groupView_ != state) + emit groupViewStateChanged(state); + + groupView_ = state; + save(); +} + +void +UserSettings::setMarkdown(bool state) +{ + if (state == markdown_) + return; + markdown_ = state; + emit markdownChanged(state); + save(); +} + +void +UserSettings::setReadReceipts(bool state) +{ + if (state == readReceipts_) + return; + readReceipts_ = state; + emit readReceiptsChanged(state); + save(); +} + +void +UserSettings::setTypingNotifications(bool state) +{ + if (state == typingNotifications_) + return; + typingNotifications_ = state; + emit typingNotificationsChanged(state); + save(); +} + +void +UserSettings::setSortByImportance(bool state) +{ + if (state == sortByImportance_) + return; + sortByImportance_ = state; + emit roomSortingChanged(state); + save(); +} + +void +UserSettings::setButtonsInTimeline(bool state) +{ + if (state == buttonsInTimeline_) + return; + buttonsInTimeline_ = state; + emit buttonInTimelineChanged(state); + save(); +} + +void +UserSettings::setTimelineMaxWidth(int state) +{ + if (state == timelineMaxWidth_) + return; + timelineMaxWidth_ = state; + emit timelineMaxWidthChanged(state); + save(); +} + +void +UserSettings::setDesktopNotifications(bool state) +{ + if (state == hasDesktopNotifications_) + return; + hasDesktopNotifications_ = state; + emit desktopNotificationsChanged(state); + save(); +} + +void +UserSettings::setAvatarCircles(bool state) +{ + if (state == avatarCircles_) + return; + avatarCircles_ = state; + emit avatarCirclesChanged(state); + save(); +} + +void +UserSettings::setDecryptSidebar(bool state) +{ + if (state == decryptSidebar_) + return; + decryptSidebar_ = state; + emit decryptSidebarChanged(state); + save(); +} void UserSettings::setFontSize(double size) { + if (size == baseFontSize_) + return; baseFontSize_ = size; + emit fontSizeChanged(size); save(); } void UserSettings::setFontFamily(QString family) { + if (family == font_) + return; font_ = family; + emit fontChanged(family); save(); } void UserSettings::setEmojiFontFamily(QString family) { + if (family == emojiFont_) + return; emojiFont_ = family; + emit emojiFontChanged(family); save(); } void UserSettings::setTheme(QString theme) { + if (theme == theme) + return; theme_ = theme; save(); applyTheme(); + emit themeChanged(theme); } void @@ -161,29 +314,33 @@ UserSettings::save() settings.beginGroup("user"); settings.beginGroup("window"); - settings.setValue("tray", isTrayEnabled_); - settings.setValue("start_in_tray", isStartInTrayEnabled_); + settings.setValue("tray", tray_); + settings.setValue("start_in_tray", startInTray_); settings.endGroup(); settings.beginGroup("timeline"); - settings.setValue("buttons", isButtonsInTimelineEnabled_); - settings.setValue("message_hover_highlight", isMessageHoverHighlightEnabled_); + settings.setValue("buttons", buttonsInTimeline_); + settings.setValue("message_hover_highlight", messageHoverHighlight_); + settings.setValue("enlarge_emoji_only_msg", enlargeEmojiOnlyMessages_); + settings.setValue("max_width", timelineMaxWidth_); settings.endGroup(); settings.setValue("avatar_circles", avatarCircles_); settings.setValue("decrypt_sidebar", decryptSidebar_); settings.setValue("font_size", baseFontSize_); - settings.setValue("typing_notifications", isTypingNotificationsEnabled_); + settings.setValue("typing_notifications", typingNotifications_); settings.setValue("minor_events", sortByImportance_); - settings.setValue("read_receipts", isReadReceiptsEnabled_); - settings.setValue("group_view", isGroupViewEnabled_); - settings.setValue("markdown_enabled", isMarkdownEnabled_); + settings.setValue("read_receipts", readReceipts_); + settings.setValue("group_view", groupView_); + settings.setValue("markdown_enabled", markdown_); settings.setValue("desktop_notifications", hasDesktopNotifications_); settings.setValue("theme", theme()); settings.setValue("font_family", font_); settings.setValue("emoji_font_family", emojiFont_); settings.endGroup(); + + settings.sync(); } HorizontalLine::HorizontalLine(QWidget *parent) @@ -231,24 +388,26 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge general_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); general_->setFont(font); - trayToggle_ = new Toggle{this}; - startInTrayToggle_ = new Toggle{this}; - avatarCircles_ = new Toggle{this}; - decryptSidebar_ = new Toggle(this); - groupViewToggle_ = new Toggle{this}; - timelineButtonsToggle_ = new Toggle{this}; - typingNotifications_ = new Toggle{this}; - messageHoverHighlight_ = new Toggle{this}; - sortByImportance_ = new Toggle{this}; - readReceipts_ = new Toggle{this}; - markdownEnabled_ = new Toggle{this}; - desktopNotifications_ = new Toggle{this}; - scaleFactorCombo_ = new QComboBox{this}; - fontSizeCombo_ = new QComboBox{this}; - fontSelectionCombo_ = new QComboBox{this}; - emojiFontSelectionCombo_ = new QComboBox{this}; + trayToggle_ = new Toggle{this}; + startInTrayToggle_ = new Toggle{this}; + avatarCircles_ = new Toggle{this}; + decryptSidebar_ = new Toggle(this); + groupViewToggle_ = new Toggle{this}; + timelineButtonsToggle_ = new Toggle{this}; + typingNotifications_ = new Toggle{this}; + messageHoverHighlight_ = new Toggle{this}; + enlargeEmojiOnlyMessages_ = new Toggle{this}; + sortByImportance_ = new Toggle{this}; + readReceipts_ = new Toggle{this}; + markdown_ = new Toggle{this}; + desktopNotifications_ = new Toggle{this}; + scaleFactorCombo_ = new QComboBox{this}; + fontSizeCombo_ = new QComboBox{this}; + fontSelectionCombo_ = new QComboBox{this}; + emojiFontSelectionCombo_ = new QComboBox{this}; + timelineMaxWidthSpin_ = new QSpinBox{this}; - if (!settings_->isTrayEnabled()) + if (!settings_->tray()) startInTrayToggle_->setDisabled(true); avatarCircles_->setFixedSize(64, 48); @@ -291,6 +450,10 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge int themeIndex = themeCombo_->findText(themeStr); themeCombo_->setCurrentIndex(themeIndex); + timelineMaxWidthSpin_->setMinimum(0); + timelineMaxWidthSpin_->setMaximum(100'000'000); + timelineMaxWidthSpin_->setSingleStep(10); + auto encryptionLabel_ = new QLabel{tr("ENCRYPTION"), this}; encryptionLabel_->setFixedHeight(encryptionLabel_->minimumHeight() + LayoutTopMargin); encryptionLabel_->setAlignment(Qt::AlignBottom); @@ -323,11 +486,15 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge sessionKeysLayout->addWidget(sessionKeysExportBtn, 0, Qt::AlignRight); sessionKeysLayout->addWidget(sessionKeysImportBtn, 0, Qt::AlignRight); - auto boxWrap = [this, &font](QString labelText, QWidget *field) { + auto boxWrap = [this, &font](QString labelText, QWidget *field, QString tooltipText = "") { auto label = new QLabel{labelText, this}; label->setFont(font); label->setMargin(OptionMargin); + if (!tooltipText.isEmpty()) { + label->setToolTip(tooltipText); + } + auto layout = new QHBoxLayout; layout->addWidget(field, 0, Qt::AlignRight); @@ -336,25 +503,70 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge formLayout_->addRow(general_); formLayout_->addRow(new HorizontalLine{this}); - boxWrap(tr("Minimize to tray"), trayToggle_); - boxWrap(tr("Start in tray"), startInTrayToggle_); + boxWrap( + tr("Minimize to tray"), + trayToggle_, + tr("Keep the application running in the background after closing the client window.")); + boxWrap(tr("Start in tray"), + startInTrayToggle_, + tr("Start the application in the background without showing the client window.")); formLayout_->addRow(new HorizontalLine{this}); - boxWrap(tr("Circular Avatars"), avatarCircles_); - boxWrap(tr("Group's sidebar"), groupViewToggle_); - boxWrap(tr("Decrypt messages in sidebar"), decryptSidebar_); - boxWrap(tr("Show buttons in timeline"), timelineButtonsToggle_); - boxWrap(tr("Typing notifications"), typingNotifications_); - boxWrap(tr("Sort rooms by unreads"), sortByImportance_); + boxWrap(tr("Circular Avatars"), + avatarCircles_, + tr("Change the appearance of user avatars in chats.\nOFF - square, ON - Circle.")); + boxWrap(tr("Group's sidebar"), + groupViewToggle_, + tr("Show a column containing groups and tags next to the room list.")); + boxWrap(tr("Decrypt messages in sidebar"), + decryptSidebar_, + tr("Decrypt the messages shown in the sidebar.\nOnly affects messages in " + "encrypted chats.")); + boxWrap(tr("Show buttons in timeline"), + timelineButtonsToggle_, + tr("Show buttons to quickly reply, react or access additional options next to each " + "message.")); + boxWrap(tr("Limit width of timeline"), + timelineMaxWidthSpin_, + tr("Set the max width of messages in the timeline (in pixels). This can help " + "readability on wide screen, when Nheko is maximised")); + boxWrap(tr("Typing notifications"), + typingNotifications_, + tr("Show who is typing in a room.\nThis will also enable or disable sending typing " + "notifications to others.")); + boxWrap( + tr("Sort rooms by unreads"), + sortByImportance_, + tr( + "Display rooms with new messages first.\nIf this is off, the list of rooms will only " + "be sorted by the timestamp of the last message in a room.\nIf this is on, rooms which " + "have active notifications (the small circle with a number in it) will be sorted on " + "top. Rooms, that you have muted, will still be sorted by timestamp, since you don't " + "seem to consider them as important as the other rooms.")); formLayout_->addRow(new HorizontalLine{this}); - boxWrap(tr("Read receipts"), readReceipts_); - boxWrap(tr("Send messages as Markdown"), markdownEnabled_); - boxWrap(tr("Desktop notifications"), desktopNotifications_); - boxWrap(tr("Highlight message on hover"), messageHoverHighlight_); + boxWrap(tr("Read receipts"), + readReceipts_, + tr("Show if your message was read.\nStatus is displayed next to timestamps.")); + boxWrap( + tr("Send messages as Markdown"), + markdown_, + tr("Allow using markdown in messages.\nWhen disabled, all messages are sent as a plain " + "text.")); + boxWrap(tr("Desktop notifications"), + desktopNotifications_, + tr("Notify about received message when the client is not currently focused.")); + boxWrap(tr("Highlight message on hover"), + messageHoverHighlight_, + tr("Change the background color of messages when you hover over them.")); + boxWrap(tr("Large Emoji in timeline"), + enlargeEmojiOnlyMessages_, + tr("Make font size larger if messages with only a few emojis are displayed.")); formLayout_->addRow(uiLabel_); formLayout_->addRow(new HorizontalLine{this}); #if !defined(Q_OS_MAC) - boxWrap(tr("Scale factor"), scaleFactorCombo_); + boxWrap(tr("Scale factor"), + scaleFactorCombo_, + tr("Change the scale factor of the whole user interface.")); #else scaleFactorCombo_->hide(); #endif @@ -400,78 +612,87 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge topLayout_->addWidget(versionInfo); connect(themeCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &text) { settings_->setTheme(text.toLower()); emit themeChanged(); }); connect(scaleFactorCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [](const QString &factor) { utils::setScaleFactor(factor.toFloat()); }); connect(fontSizeCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &size) { settings_->setFontSize(size.trimmed().toDouble()); }); connect(fontSelectionCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &family) { settings_->setFontFamily(family.trimmed()); }); connect(emojiFontSelectionCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &family) { settings_->setEmojiFontFamily(family.trimmed()); }); - connect(trayToggle_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setTray(!isDisabled); - if (isDisabled) { + connect(trayToggle_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setTray(!disabled); + if (disabled) { startInTrayToggle_->setDisabled(true); } else { startInTrayToggle_->setEnabled(true); } - emit trayOptionChanged(!isDisabled); + emit trayOptionChanged(!disabled); }); - connect(startInTrayToggle_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setStartInTray(!isDisabled); + connect(startInTrayToggle_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setStartInTray(!disabled); }); - connect(groupViewToggle_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setGroupView(!isDisabled); + connect(groupViewToggle_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setGroupView(!disabled); }); - connect(decryptSidebar_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setDecryptSidebar(!isDisabled); + connect(decryptSidebar_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setDecryptSidebar(!disabled); emit decryptSidebarChanged(); }); - connect(avatarCircles_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setAvatarCircles(!isDisabled); + connect(avatarCircles_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setAvatarCircles(!disabled); }); - connect(markdownEnabled_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setMarkdownEnabled(!isDisabled); + connect(markdown_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setMarkdown(!disabled); }); - connect(typingNotifications_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setTypingNotifications(!isDisabled); + connect(typingNotifications_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setTypingNotifications(!disabled); }); - connect(sortByImportance_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setSortByImportance(!isDisabled); + connect(sortByImportance_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setSortByImportance(!disabled); }); - connect(timelineButtonsToggle_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setButtonsInTimeline(!isDisabled); + connect(timelineButtonsToggle_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setButtonsInTimeline(!disabled); }); - connect(readReceipts_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setReadReceipts(!isDisabled); + connect(readReceipts_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setReadReceipts(!disabled); }); - connect(desktopNotifications_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setDesktopNotifications(!isDisabled); + connect(desktopNotifications_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setDesktopNotifications(!disabled); }); - connect(messageHoverHighlight_, &Toggle::toggled, this, [this](bool isDisabled) { - settings_->setMessageHoverHighlight(!isDisabled); + connect(messageHoverHighlight_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setMessageHoverHighlight(!disabled); }); + connect(enlargeEmojiOnlyMessages_, &Toggle::toggled, this, [this](bool disabled) { + settings_->setEnlargeEmojiOnlyMessages(!disabled); + }); + + connect(timelineMaxWidthSpin_, + qOverload<int>(&QSpinBox::valueChanged), + this, + [this](int newValue) { settings_->setTimelineMaxWidth(newValue); }); + connect( sessionKeysImportBtn, &QPushButton::clicked, this, &UserSettingsPage::importSessionKeys); @@ -493,19 +714,21 @@ UserSettingsPage::showEvent(QShowEvent *) utils::restoreCombobox(themeCombo_, settings_->theme()); // FIXME: Toggle treats true as "off" - trayToggle_->setState(!settings_->isTrayEnabled()); - startInTrayToggle_->setState(!settings_->isStartInTrayEnabled()); - groupViewToggle_->setState(!settings_->isGroupViewEnabled()); - decryptSidebar_->setState(!settings_->isDecryptSidebarEnabled()); - avatarCircles_->setState(!settings_->isAvatarCirclesEnabled()); - typingNotifications_->setState(!settings_->isTypingNotificationsEnabled()); - sortByImportance_->setState(!settings_->isSortByImportanceEnabled()); - timelineButtonsToggle_->setState(!settings_->isButtonsInTimelineEnabled()); - readReceipts_->setState(!settings_->isReadReceiptsEnabled()); - markdownEnabled_->setState(!settings_->isMarkdownEnabled()); + trayToggle_->setState(!settings_->tray()); + startInTrayToggle_->setState(!settings_->startInTray()); + groupViewToggle_->setState(!settings_->groupView()); + decryptSidebar_->setState(!settings_->decryptSidebar()); + avatarCircles_->setState(!settings_->avatarCircles()); + typingNotifications_->setState(!settings_->typingNotifications()); + sortByImportance_->setState(!settings_->sortByImportance()); + timelineButtonsToggle_->setState(!settings_->buttonsInTimeline()); + readReceipts_->setState(!settings_->readReceipts()); + markdown_->setState(!settings_->markdown()); desktopNotifications_->setState(!settings_->hasDesktopNotifications()); - messageHoverHighlight_->setState(!settings_->isMessageHoverHighlightEnabled()); + messageHoverHighlight_->setState(!settings_->messageHoverHighlight()); + enlargeEmojiOnlyMessages_->setState(!settings_->enlargeEmojiOnlyMessages()); deviceIdValue_->setText(QString::fromStdString(http::client()->device_id())); + timelineMaxWidthSpin_->setValue(settings_->timelineMaxWidth()); deviceFingerprintValue_->setText( utils::humanReadableFingerprint(olm::client()->identity_keys().ed25519)); diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index 088bbfb5..fb807067 100644 --- a/src/UserSettingsPage.h +++ b/src/UserSettingsPage.h
@@ -17,17 +17,19 @@ #pragma once -#include <QComboBox> #include <QFontDatabase> -#include <QFormLayout> #include <QFrame> -#include <QLabel> -#include <QLayout> #include <QProcessEnvironment> #include <QSharedPointer> #include <QWidget> class Toggle; +class QLabel; +class QFormLayout; +class QComboBox; +class QSpinBox; +class QHBoxLayout; +class QVBoxLayout; constexpr int OptionMargin = 6; constexpr int LayoutTopMargin = 50; @@ -37,6 +39,36 @@ class UserSettings : public QObject { Q_OBJECT + Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) + Q_PROPERTY(bool messageHoverHighlight READ messageHoverHighlight WRITE + setMessageHoverHighlight NOTIFY messageHoverHighlightChanged) + Q_PROPERTY(bool enlargeEmojiOnlyMessages READ enlargeEmojiOnlyMessages WRITE + setEnlargeEmojiOnlyMessages NOTIFY enlargeEmojiOnlyMessagesChanged) + Q_PROPERTY(bool tray READ tray WRITE setTray NOTIFY trayChanged) + Q_PROPERTY(bool startInTray READ startInTray WRITE setStartInTray NOTIFY startInTrayChanged) + Q_PROPERTY(bool groupView READ groupView WRITE setGroupView NOTIFY groupViewStateChanged) + Q_PROPERTY(bool markdown READ markdown WRITE setMarkdown NOTIFY markdownChanged) + Q_PROPERTY(bool typingNotifications READ typingNotifications WRITE setTypingNotifications + NOTIFY typingNotificationsChanged) + Q_PROPERTY(bool sortByImportance READ sortByImportance WRITE setSortByImportance NOTIFY + roomSortingChanged) + Q_PROPERTY(bool buttonsInTimeline READ buttonsInTimeline WRITE setButtonsInTimeline NOTIFY + buttonInTimelineChanged) + Q_PROPERTY( + bool readReceipts READ readReceipts WRITE setReadReceipts NOTIFY readReceiptsChanged) + Q_PROPERTY(bool desktopNotifications READ hasDesktopNotifications WRITE + setDesktopNotifications NOTIFY desktopNotificationsChanged) + Q_PROPERTY( + bool avatarCircles READ avatarCircles WRITE setAvatarCircles NOTIFY avatarCirclesChanged) + Q_PROPERTY(bool decryptSidebar READ decryptSidebar WRITE setDecryptSidebar NOTIFY + decryptSidebarChanged) + Q_PROPERTY(int timelineMaxWidth READ timelineMaxWidth WRITE setTimelineMaxWidth NOTIFY + timelineMaxWidthChanged) + Q_PROPERTY(double fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged) + Q_PROPERTY(QString font READ font WRITE setFontFamily NOTIFY fontChanged) + Q_PROPERTY( + QString emojiFont READ emojiFont WRITE setEmojiFontFamily NOTIFY emojiFontChanged) + public: UserSettings(); @@ -44,104 +76,62 @@ public: void load(); void applyTheme(); void setTheme(QString theme); - void setMessageHoverHighlight(bool state) - { - isMessageHoverHighlightEnabled_ = state; - save(); - } - void setTray(bool state) - { - isTrayEnabled_ = state; - save(); - } - - void setStartInTray(bool state) - { - isStartInTrayEnabled_ = state; - save(); - } - + void setMessageHoverHighlight(bool state); + void setEnlargeEmojiOnlyMessages(bool state); + void setTray(bool state); + void setStartInTray(bool state); void setFontSize(double size); void setFontFamily(QString family); void setEmojiFontFamily(QString family); - - void setGroupView(bool state) - { - if (isGroupViewEnabled_ != state) - emit groupViewStateChanged(state); - - isGroupViewEnabled_ = state; - save(); - } - - void setMarkdownEnabled(bool state) - { - isMarkdownEnabled_ = state; - save(); - } - - void setReadReceipts(bool state) - { - isReadReceiptsEnabled_ = state; - save(); - } - - void setTypingNotifications(bool state) - { - isTypingNotificationsEnabled_ = state; - save(); - } - - void setSortByImportance(bool state) - { - sortByImportance_ = state; - emit roomSortingChanged(); - } - - void setButtonsInTimeline(bool state) - { - isButtonsInTimelineEnabled_ = state; - save(); - } - - void setDesktopNotifications(bool state) - { - hasDesktopNotifications_ = state; - save(); - } - - void setAvatarCircles(bool state) - { - avatarCircles_ = state; - save(); - } - - void setDecryptSidebar(bool state) - { - decryptSidebar_ = state; - save(); - } + void setGroupView(bool state); + void setMarkdown(bool state); + void setReadReceipts(bool state); + void setTypingNotifications(bool state); + void setSortByImportance(bool state); + void setButtonsInTimeline(bool state); + void setTimelineMaxWidth(int state); + void setDesktopNotifications(bool state); + void setAvatarCircles(bool state); + void setDecryptSidebar(bool state); QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; } - bool isMessageHoverHighlightEnabled() const { return isMessageHoverHighlightEnabled_; } - bool isTrayEnabled() const { return isTrayEnabled_; } - bool isStartInTrayEnabled() const { return isStartInTrayEnabled_; } - bool isGroupViewEnabled() const { return isGroupViewEnabled_; } - bool isAvatarCirclesEnabled() const { return avatarCircles_; } - bool isDecryptSidebarEnabled() const { return decryptSidebar_; } - bool isMarkdownEnabled() const { return isMarkdownEnabled_; } - bool isTypingNotificationsEnabled() const { return isTypingNotificationsEnabled_; } - bool isSortByImportanceEnabled() const { return sortByImportance_; } - bool isButtonsInTimelineEnabled() const { return isButtonsInTimelineEnabled_; } - bool isReadReceiptsEnabled() const { return isReadReceiptsEnabled_; } + bool messageHoverHighlight() const { return messageHoverHighlight_; } + bool enlargeEmojiOnlyMessages() const { return enlargeEmojiOnlyMessages_; } + bool tray() const { return tray_; } + bool startInTray() const { return startInTray_; } + bool groupView() const { return groupView_; } + bool avatarCircles() const { return avatarCircles_; } + bool decryptSidebar() const { return decryptSidebar_; } + bool markdown() const { return markdown_; } + bool typingNotifications() const { return typingNotifications_; } + bool sortByImportance() const { return sortByImportance_; } + bool buttonsInTimeline() const { return buttonsInTimeline_; } + bool readReceipts() const { return readReceipts_; } bool hasDesktopNotifications() const { return hasDesktopNotifications_; } + int timelineMaxWidth() const { return timelineMaxWidth_; } double fontSize() const { return baseFontSize_; } QString font() const { return font_; } QString emojiFont() const { return emojiFont_; } signals: void groupViewStateChanged(bool state); - void roomSortingChanged(); + void roomSortingChanged(bool state); + void themeChanged(QString state); + void messageHoverHighlightChanged(bool state); + void enlargeEmojiOnlyMessagesChanged(bool state); + void trayChanged(bool state); + void startInTrayChanged(bool state); + void markdownChanged(bool state); + void typingNotificationsChanged(bool state); + void buttonInTimelineChanged(bool state); + void readReceiptsChanged(bool state); + void desktopNotificationsChanged(bool state); + void avatarCirclesChanged(bool state); + void decryptSidebarChanged(bool state); + void timelineMaxWidthChanged(int state); + void fontSizeChanged(double state); + void fontChanged(QString state); + void emojiFontChanged(QString state); private: // Default to system theme if QT_QPA_PLATFORMTHEME var is set. @@ -150,18 +140,20 @@ private: ? "light" : "system"; QString theme_; - bool isMessageHoverHighlightEnabled_; - bool isTrayEnabled_; - bool isStartInTrayEnabled_; - bool isGroupViewEnabled_; - bool isMarkdownEnabled_; - bool isTypingNotificationsEnabled_; + bool messageHoverHighlight_; + bool enlargeEmojiOnlyMessages_; + bool tray_; + bool startInTray_; + bool groupView_; + bool markdown_; + bool typingNotifications_; bool sortByImportance_; - bool isButtonsInTimelineEnabled_; - bool isReadReceiptsEnabled_; + bool buttonsInTimeline_; + bool readReceipts_; bool hasDesktopNotifications_; bool avatarCircles_; bool decryptSidebar_; + int timelineMaxWidth_; double baseFontSize_; QString font_; QString emojiFont_; @@ -211,9 +203,10 @@ private: Toggle *timelineButtonsToggle_; Toggle *typingNotifications_; Toggle *messageHoverHighlight_; + Toggle *enlargeEmojiOnlyMessages_; Toggle *sortByImportance_; Toggle *readReceipts_; - Toggle *markdownEnabled_; + Toggle *markdown_; Toggle *desktopNotifications_; Toggle *avatarCircles_; Toggle *decryptSidebar_; @@ -226,5 +219,7 @@ private: QComboBox *fontSelectionCombo_; QComboBox *emojiFontSelectionCombo_; + QSpinBox *timelineMaxWidthSpin_; + int sideMargin_ = 0; }; diff --git a/src/Utils.cpp b/src/Utils.cpp
index 7f11a8cd..26ea124c 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp
@@ -51,6 +51,14 @@ utils::localUser() return QString::fromStdString(http::client()->user_id().to_string()); } +bool +utils::codepointIsEmoji(uint code) +{ + // TODO: Be more precise here. + return (code >= 0x2600 && code <= 0x27bf) || (code >= 0x1f300 && code <= 0x1f3ff) || + (code >= 0x1f000 && code <= 0x1faff); +} + QString utils::replaceEmoji(const QString &body) { @@ -63,9 +71,7 @@ utils::replaceEmoji(const QString &body) bool insideFontBlock = false; for (auto &code : utf32_string) { - // TODO: Be more precise here. - if ((code >= 0x2600 && code <= 0x27bf) || (code >= 0x1f300 && code <= 0x1f3ff) || - (code >= 0x1f000 && code <= 0x1faff)) { + if (utils::codepointIsEmoji(code)) { if (!insideFontBlock) { fmtBody += QString("<font face=\"" + userFontFamily + "\">"); insideFontBlock = true; @@ -136,13 +142,13 @@ utils::descriptiveTime(const QDateTime &then) const auto days = then.daysTo(now); if (days == 0) - return then.time().toString(Qt::DefaultLocaleShortDate); + return QLocale::system().toString(then.time(), QLocale::ShortFormat); else if (days < 2) return QString(QCoreApplication::translate("descriptiveTime", "Yesterday")); else if (days < 7) return then.toString("dddd"); - return then.date().toString(Qt::DefaultLocaleShortDate); + return QLocale::system().toString(then.date(), QLocale::ShortFormat); } DescInfo diff --git a/src/Utils.h b/src/Utils.h
index d3f66246..07a4a648 100644 --- a/src/Utils.h +++ b/src/Utils.h
@@ -36,6 +36,9 @@ namespace utils { using TimelineEvent = mtx::events::collections::TimelineEvents; +bool +codepointIsEmoji(uint code); + QString replaceEmoji(const QString &body); @@ -183,42 +186,6 @@ erase_if(ContainerT &items, const PredicateT &predicate) } } -inline uint64_t -event_timestamp(const mtx::events::collections::TimelineEvents &event) -{ - return std::visit([](auto msg) { return msg.origin_server_ts; }, event); -} - -inline nlohmann::json -serialize_event(const mtx::events::collections::TimelineEvents &event) -{ - return std::visit([](auto msg) { return json(msg); }, event); -} - -inline mtx::events::EventType -event_type(const mtx::events::collections::TimelineEvents &event) -{ - return std::visit([](auto msg) { return msg.type; }, event); -} - -inline std::string -event_id(const mtx::events::collections::TimelineEvents &event) -{ - return std::visit([](auto msg) { return msg.event_id; }, event); -} - -inline QString -eventId(const mtx::events::collections::TimelineEvents &event) -{ - return QString::fromStdString(event_id(event)); -} - -inline QString -event_sender(const mtx::events::collections::TimelineEvents &event) -{ - return std::visit([](auto msg) { return QString::fromStdString(msg.sender); }, event); -} - template<class T> QString message_body(const mtx::events::collections::TimelineEvents &event) diff --git a/src/dialogs/CreateRoom.cpp b/src/dialogs/CreateRoom.cpp
index 06676d3d..be5b4638 100644 --- a/src/dialogs/CreateRoom.cpp +++ b/src/dialogs/CreateRoom.cpp
@@ -112,7 +112,7 @@ CreateRoom::CreateRoom(QWidget *parent) }); connect(visibilityCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &text) { if (text == "Private") { request_.visibility = mtx::requests::Visibility::Private; @@ -122,7 +122,7 @@ CreateRoom::CreateRoom(QWidget *parent) }); connect(presetCombo_, - static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated), + static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), [this](const QString &text) { if (text == "Private Chat") { request_.preset = mtx::requests::Preset::PrivateChat; diff --git a/src/dialogs/InviteUsers.cpp b/src/dialogs/InviteUsers.cpp
index 691035ce..f85adb8f 100644 --- a/src/dialogs/InviteUsers.cpp +++ b/src/dialogs/InviteUsers.cpp
@@ -1,5 +1,6 @@ #include <QDebug> #include <QIcon> +#include <QLabel> #include <QListWidget> #include <QListWidgetItem> #include <QPushButton> diff --git a/src/dialogs/InviteUsers.h b/src/dialogs/InviteUsers.h
index 952c97a5..684f60b4 100644 --- a/src/dialogs/InviteUsers.h +++ b/src/dialogs/InviteUsers.h
@@ -1,13 +1,13 @@ #pragma once #include <QFrame> -#include <QLabel> -#include <QListWidgetItem> #include <QStringList> class QPushButton; +class QLabel; class TextField; class QListWidget; +class QListWidgetItem; namespace dialogs { diff --git a/src/dialogs/ReadReceipts.cpp b/src/dialogs/ReadReceipts.cpp
index 0edd1ebf..7dcffc28 100644 --- a/src/dialogs/ReadReceipts.cpp +++ b/src/dialogs/ReadReceipts.cpp
@@ -1,5 +1,6 @@ #include <QDebug> #include <QIcon> +#include <QLabel> #include <QListWidgetItem> #include <QPainter> #include <QPushButton> @@ -74,15 +75,17 @@ ReceiptItem::dateFormat(const QDateTime &then) const auto days = then.daysTo(now); if (days == 0) - return tr("Today %1").arg(then.time().toString(Qt::DefaultLocaleShortDate)); + return tr("Today %1") + .arg(QLocale::system().toString(then.time(), QLocale::ShortFormat)); else if (days < 2) - return tr("Yesterday %1").arg(then.time().toString(Qt::DefaultLocaleShortDate)); + return tr("Yesterday %1") + .arg(QLocale::system().toString(then.time(), QLocale::ShortFormat)); else if (days < 7) return QString("%1 %2") .arg(then.toString("dddd")) - .arg(then.time().toString(Qt::DefaultLocaleShortDate)); + .arg(QLocale::system().toString(then.time(), QLocale::ShortFormat)); - return then.toString(Qt::DefaultLocaleShortDate); + return QLocale::system().toString(then.time(), QLocale::ShortFormat); } ReadReceipts::ReadReceipts(QWidget *parent) @@ -163,3 +166,10 @@ ReadReceipts::paintEvent(QPaintEvent *) QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } + +void +ReadReceipts::hideEvent(QHideEvent *event) +{ + userList_->clear(); + QFrame::hideEvent(event); +} diff --git a/src/dialogs/ReadReceipts.h b/src/dialogs/ReadReceipts.h
index e298af0a..2e7a0217 100644 --- a/src/dialogs/ReadReceipts.h +++ b/src/dialogs/ReadReceipts.h
@@ -2,12 +2,12 @@ #include <QDateTime> #include <QFrame> -#include <QHBoxLayout> -#include <QLabel> -#include <QListWidget> -#include <QVBoxLayout> class Avatar; +class QLabel; +class QListWidget; +class QHBoxLayout; +class QVBoxLayout; namespace dialogs { @@ -47,11 +47,7 @@ public slots: protected: void paintEvent(QPaintEvent *event) override; - void hideEvent(QHideEvent *event) override - { - userList_->clear(); - QFrame::hideEvent(event); - } + void hideEvent(QHideEvent *event) override; private: QLabel *topLabel_; diff --git a/src/dialogs/RoomSettings.cpp b/src/dialogs/RoomSettings.cpp
index cc10ac91..26aece32 100644 --- a/src/dialogs/RoomSettings.cpp +++ b/src/dialogs/RoomSettings.cpp
@@ -1,5 +1,6 @@ #include <QApplication> #include <QComboBox> +#include <QEvent> #include <QFileDialog> #include <QFontDatabase> #include <QImageReader> @@ -41,6 +42,17 @@ constexpr int WIDGET_SPACING = 15; constexpr int TEXT_SPACING = 4; constexpr int BUTTON_SPACING = 2 * TEXT_SPACING; +bool +ClickableFilter::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::MouseButtonRelease) { + emit clicked(); + return true; + } + + return QObject::eventFilter(obj, event); +} + EditModal::EditModal(const QString &roomId, QWidget *parent) : QWidget(parent) , roomId_{roomId} @@ -94,6 +106,28 @@ EditModal::EditModal(const QString &roomId, QWidget *parent) } void +EditModal::topicEventSent() +{ + errorField_->hide(); + close(); +} + +void +EditModal::nameEventSent(const QString &name) +{ + errorField_->hide(); + emit nameChanged(name); + close(); +} + +void +EditModal::error(const QString &msg) +{ + errorField_->setText(msg); + errorField_->show(); +} + +void EditModal::applyClicked() { // Check if the values are changed from the originals. diff --git a/src/dialogs/RoomSettings.h b/src/dialogs/RoomSettings.h
index e41c866c..e0918afd 100644 --- a/src/dialogs/RoomSettings.h +++ b/src/dialogs/RoomSettings.h
@@ -1,9 +1,7 @@ #pragma once -#include <QEvent> #include <QFrame> #include <QImage> -#include <QLabel> #include <mtx/events/guest_access.hpp> @@ -21,6 +19,8 @@ class QPixmap; class TextField; class TextField; class Toggle; +class QLabel; +class QEvent; class ClickableFilter : public QObject { @@ -35,15 +35,7 @@ signals: void clicked(); protected: - bool eventFilter(QObject *obj, QEvent *event) override - { - if (event->type() == QEvent::MouseButtonRelease) { - emit clicked(); - return true; - } - - return QObject::eventFilter(obj, event); - } + bool eventFilter(QObject *obj, QEvent *event) override; }; /// Convenience class which connects events emmited from threads @@ -72,24 +64,9 @@ signals: void nameChanged(const QString &roomName); private slots: - void topicEventSent() - { - errorField_->hide(); - close(); - } - - void nameEventSent(const QString &name) - { - errorField_->hide(); - emit nameChanged(name); - close(); - } - - void error(const QString &msg) - { - errorField_->setText(msg); - errorField_->show(); - } + void topicEventSent(); + void nameEventSent(const QString &name); + void error(const QString &msg); void applyClicked(); diff --git a/src/emoji/Category.cpp b/src/emoji/Category.cpp
index 7393b7bc..1e8df082 100644 --- a/src/emoji/Category.cpp +++ b/src/emoji/Category.cpp
@@ -15,9 +15,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <QLabel> +#include <QListView> #include <QPainter> #include <QScrollBar> #include <QStyleOption> +#include <QVBoxLayout> #include "Config.h" diff --git a/src/emoji/Category.h b/src/emoji/Category.h
index 2f39d621..79e616ee 100644 --- a/src/emoji/Category.h +++ b/src/emoji/Category.h
@@ -18,13 +18,14 @@ #pragma once #include <QColor> -#include <QLabel> -#include <QLayout> -#include <QListView> -#include <QStandardItemModel> #include "ItemDelegate.h" +class QLabel; +class QListView; +class QStandardItemModel; +class QVBoxLayout; + namespace emoji { class Category : public QWidget diff --git a/src/popups/PopupItem.cpp b/src/popups/PopupItem.cpp
index 5513f942..b3784843 100644 --- a/src/popups/PopupItem.cpp +++ b/src/popups/PopupItem.cpp
@@ -1,3 +1,4 @@ +#include <QLabel> #include <QPaintEvent> #include <QPainter> #include <QStyleOption> diff --git a/src/popups/PopupItem.h b/src/popups/PopupItem.h
index 7a710fdb..17a4f6bc 100644 --- a/src/popups/PopupItem.h +++ b/src/popups/PopupItem.h
@@ -1,8 +1,5 @@ #pragma once -#include <QHBoxLayout> -#include <QLabel> -#include <QPoint> #include <QWidget> #include "../AvatarProvider.h" @@ -10,6 +7,8 @@ class Avatar; struct SearchResult; +class QLabel; +class QHBoxLayout; class PopupItem : public QWidget { diff --git a/src/popups/SuggestionsPopup.h b/src/popups/SuggestionsPopup.h
index 63c44538..73bfe6f7 100644 --- a/src/popups/SuggestionsPopup.h +++ b/src/popups/SuggestionsPopup.h
@@ -1,8 +1,5 @@ #pragma once -#include <QHBoxLayout> -#include <QLabel> -#include <QPoint> #include <QWidget> #include "CacheStructs.h" diff --git a/src/popups/UserMentions.cpp b/src/popups/UserMentions.cpp
index 2e70dbd3..23a679f1 100644 --- a/src/popups/UserMentions.cpp +++ b/src/popups/UserMentions.cpp
@@ -8,9 +8,9 @@ #include "Cache.h" #include "ChatPage.h" +#include "EventAccessors.h" #include "Logging.h" #include "UserMentions.h" -//#include "timeline/TimelineItem.h" using namespace popups; @@ -75,12 +75,15 @@ UserMentions::initializeMentions(const QMap<QString, mtx::responses::Notificatio for (const auto &item : notifs) { for (const auto &notif : item.notifications) { - const auto event_id = QString::fromStdString(utils::event_id(notif.event)); + const auto event_id = + QString::fromStdString(mtx::accessors::event_id(notif.event)); try { const auto room_id = QString::fromStdString(notif.room_id); - const auto user_id = utils::event_sender(notif.event); - const auto body = utils::event_body(notif.event); + const auto user_id = + QString::fromStdString(mtx::accessors::sender(notif.event)); + const auto body = + QString::fromStdString(mtx::accessors::body(notif.event)); pushItem(event_id, user_id, diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 371e9f58..95997eb8 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp
@@ -219,6 +219,7 @@ TimelineModel::roleNames() const {Section, "section"}, {Type, "type"}, {TypeString, "typeString"}, + {IsOnlyEmoji, "isOnlyEmoji"}, {Body, "body"}, {FormattedBody, "formattedBody"}, {UserId, "userId"}, @@ -284,6 +285,22 @@ TimelineModel::data(const QString &id, int role) const return QVariant(toRoomEventType(event)); case TypeString: return QVariant(toRoomEventTypeString(event)); + case IsOnlyEmoji: { + QString qBody = QString::fromStdString(body(event)); + + QVector<uint> utf32_string = qBody.toUcs4(); + int emojiCount = 0; + + for (auto &code : utf32_string) { + if (utils::codepointIsEmoji(code)) { + emojiCount++; + } else { + return QVariant(0); + } + } + + return QVariant(emojiCount); + } case Body: return QVariant(utils::replaceEmoji(QString::fromStdString(body(event)))); case FormattedBody: { @@ -386,6 +403,7 @@ TimelineModel::data(const QString &id, int role) const // m.insert(names[Section], data(id, static_cast<int>(Section))); m.insert(names[Type], data(id, static_cast<int>(Type))); m.insert(names[TypeString], data(id, static_cast<int>(TypeString))); + m.insert(names[IsOnlyEmoji], data(id, static_cast<int>(IsOnlyEmoji))); m.insert(names[Body], data(id, static_cast<int>(Body))); m.insert(names[FormattedBody], data(id, static_cast<int>(FormattedBody))); m.insert(names[UserId], data(id, static_cast<int>(UserId))); @@ -810,7 +828,7 @@ TimelineModel::escapeEmoji(QString str) const void TimelineModel::viewRawMessage(QString id) const { - std::string ev = utils::serialize_event(events.value(id)).dump(4); + std::string ev = mtx::accessors::serialize_event(events.value(id)).dump(4); auto dialog = new dialogs::RawMessage(QString::fromStdString(ev)); Q_UNUSED(dialog); } @@ -824,7 +842,7 @@ TimelineModel::viewDecryptedRawMessage(QString id) const event = decryptEvent(*e).event; } - std::string ev = utils::serialize_event(event).dump(4); + std::string ev = mtx::accessors::serialize_event(event).dump(4); auto dialog = new dialogs::RawMessage(QString::fromStdString(ev)); Q_UNUSED(dialog); } @@ -1849,6 +1867,8 @@ TimelineModel::formatMemberEvent(QString id) rendered = tr("%1 changed their display name.").arg(name); else if (avatarChanged) rendered = tr("%1 changed their avatar.").arg(name); + else + rendered = tr("%1 changed some profile info.").arg(name); // the case of nothing changed but join follows join shouldn't happen, so // just show it as join } else { diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index ea7eaffd..3b01781f 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h
@@ -142,6 +142,7 @@ public: Section, Type, TypeString, + IsOnlyEmoji, Body, FormattedBody, UserId, diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 0375ccc8..bf671cb0 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp
@@ -21,7 +21,7 @@ Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents) void TimelineViewManager::updateEncryptedDescriptions() { - auto decrypt = settings->isDecryptSidebarEnabled(); + auto decrypt = settings->decryptSidebar(); QHash<QString, QSharedPointer<TimelineModel>>::iterator i; for (i = models.begin(); i != models.end(); ++i) { auto ptr = i.value(); @@ -96,6 +96,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<UserSettings> userSettin #endif container->setMinimumSize(200, 200); view->rootContext()->setContextProperty("timelineManager", this); + view->rootContext()->setContextProperty("settings", settings.data()); updateColorPalette(); view->engine()->addImageProvider("MxcImage", imgProvider); view->engine()->addImageProvider("colorimage", colorImgProvider); @@ -121,7 +122,7 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms) const auto &room_model = models.value(QString::fromStdString(room_id)); room_model->addEvents(room.timeline); - if (ChatPage::instance()->userSettings()->isTypingNotificationsEnabled()) { + if (ChatPage::instance()->userSettings()->typingNotifications()) { std::vector<QString> typing; typing.reserve(room.ephemeral.typing.size()); for (const auto &user : room.ephemeral.typing) { @@ -141,7 +142,7 @@ TimelineViewManager::addRoom(const QString &room_id) { if (!models.contains(room_id)) { QSharedPointer<TimelineModel> newRoom(new TimelineModel(this, room_id)); - newRoom->setDecryptDescription(settings->isDecryptSidebarEnabled()); + newRoom->setDecryptDescription(settings->decryptSidebar()); connect(newRoom.data(), &TimelineModel::newEncryptedImage, @@ -225,7 +226,7 @@ TimelineViewManager::queueTextMessage(const QString &msg) mtx::events::msg::Text text = {}; text.body = msg.trimmed().toStdString(); - if (settings->isMarkdownEnabled()) { + if (settings->markdown()) { text.formatted_body = utils::markdownToHtml(msg).toStdString(); // Don't send formatted_body, when we don't need to @@ -253,7 +254,7 @@ TimelineViewManager::queueTextMessage(const QString &msg) // NOTE(Nico): rich replies always need a formatted_body! text.format = "org.matrix.custom.html"; - if (settings->isMarkdownEnabled()) + if (settings->markdown()) text.formatted_body = utils::getFormattedQuoteBody(related, utils::markdownToHtml(msg)) .toStdString(); @@ -276,7 +277,7 @@ TimelineViewManager::queueEmoteMessage(const QString &msg) mtx::events::msg::Emote emote; emote.body = msg.trimmed().toStdString(); - if (html != msg.trimmed().toHtmlEscaped() && settings->isMarkdownEnabled()) { + if (html != msg.trimmed().toHtmlEscaped() && settings->markdown()) { emote.formatted_body = html.toStdString(); emote.format = "org.matrix.custom.html"; } diff --git a/src/ui/Avatar.cpp b/src/ui/Avatar.cpp
index cb77d1a8..70ebfcf2 100644 --- a/src/ui/Avatar.cpp +++ b/src/ui/Avatar.cpp
@@ -1,4 +1,5 @@ #include <QPainter> +#include <QPainterPath> #include <QSettings> #include "AvatarProvider.h" diff --git a/src/ui/InfoMessage.cpp b/src/ui/InfoMessage.cpp
index 27bc0a5f..0b69564d 100644 --- a/src/ui/InfoMessage.cpp +++ b/src/ui/InfoMessage.cpp
@@ -4,6 +4,7 @@ #include <QDateTime> #include <QLocale> #include <QPainter> +#include <QPainterPath> #include <QPen> #include <QtGlobal> diff --git a/src/ui/Painter.h b/src/ui/Painter.h
index 4d227a5a..2bb0981b 100644 --- a/src/ui/Painter.h +++ b/src/ui/Painter.h
@@ -3,6 +3,7 @@ #include <QFontMetrics> #include <QPaintDevice> #include <QPainter> +#include <QPainterPath> #include <QtGlobal> class Painter : public QPainter @@ -163,5 +164,5 @@ public: private: Painter &_painter; - QPainter::RenderHints hints_ = 0; + QPainter::RenderHints hints_ = {}; };