From fd2d4d6db3c1ed93f1860260a0519c2284b97ffa Mon Sep 17 00:00:00 2001 From: Joseph Donofry Date: Sun, 28 Jul 2019 23:14:10 -0400 Subject: Update mentions dialog Mentions are now separated into 'this room' and 'all rooms' tab., which allows the user to filter on the current room if they desire. Should add additional logic in the future to show which room the mention was in the for the 'all rooms' view. --- src/dialogs/UserMentions.cpp | 75 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 16 deletions(-) (limited to 'src/dialogs/UserMentions.cpp') diff --git a/src/dialogs/UserMentions.cpp b/src/dialogs/UserMentions.cpp index 8f56ec93..4cfcdaca 100644 --- a/src/dialogs/UserMentions.cpp +++ b/src/dialogs/UserMentions.cpp @@ -1,3 +1,4 @@ +#include #include #include "UserMentions.h" @@ -8,31 +9,50 @@ using namespace dialogs; UserMentions::UserMentions(QWidget *parent) : QWidget{parent} { + tab_layout_ = new QTabWidget(this); + top_layout_ = new QVBoxLayout(this); top_layout_->setSpacing(0); top_layout_->setMargin(0); - scroll_area_ = new QScrollArea(this); - scroll_area_->setWidgetResizable(true); - scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + local_scroll_area_ = new QScrollArea(this); + local_scroll_area_->setWidgetResizable(true); + local_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + local_scroll_widget_ = new QWidget(this); + local_scroll_widget_->setObjectName("local_scroll_widget"); + + all_scroll_area_ = new QScrollArea(this); + all_scroll_area_->setWidgetResizable(true); + all_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scroll_widget_ = new QWidget(this); - scroll_widget_->setObjectName("scroll_widget"); + all_scroll_widget_ = new QWidget(this); + all_scroll_widget_->setObjectName("all_scroll_widget"); // Height of the typing display. QFont f; f.setPointSizeF(f.pointSizeF() * 0.9); const int bottomMargin = QFontMetrics(f).height() + 6; - scroll_layout_ = new QVBoxLayout(scroll_widget_); - scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); - scroll_layout_->setSpacing(0); - scroll_layout_->setObjectName("timelinescrollarea"); + local_scroll_layout_ = new QVBoxLayout(local_scroll_widget_); + local_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); + local_scroll_layout_->setSpacing(0); + local_scroll_layout_->setObjectName("localcrollarea"); - scroll_area_->setWidget(scroll_widget_); - scroll_area_->setAlignment(Qt::AlignBottom); + all_scroll_layout_ = new QVBoxLayout(all_scroll_widget_); + all_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); + all_scroll_layout_->setSpacing(0); + all_scroll_layout_->setObjectName("allcrollarea"); - top_layout_->addWidget(scroll_area_); + local_scroll_area_->setWidget(local_scroll_widget_); + local_scroll_area_->setAlignment(Qt::AlignBottom); + + all_scroll_area_->setWidget(all_scroll_widget_); + all_scroll_area_->setAlignment(Qt::AlignBottom); + + tab_layout_->addTab(local_scroll_area_, tr("This Room")); + tab_layout_->addTab(all_scroll_area_, tr("All Rooms")); + top_layout_->addWidget(tab_layout_); setLayout(top_layout_); } @@ -41,18 +61,41 @@ void UserMentions::pushItem(const QString &event_id, const QString &user_id, const QString &body, - const QString &room_id) + const QString &room_id, + const QString ¤t_room_id) { + setUpdatesEnabled(false); + + // Add to the 'all' section TimelineItem *view_item = new TimelineItem( - mtx::events::MessageType::Text, user_id, body, true, room_id, scroll_widget_); + mtx::events::MessageType::Text, user_id, body, true, room_id, all_scroll_widget_); view_item->setEventId(event_id); - setUpdatesEnabled(false); view_item->hide(); - scroll_layout_->addWidget(view_item); + all_scroll_layout_->addWidget(view_item); QTimer::singleShot(0, this, [view_item, this]() { view_item->show(); view_item->adjustSize(); setUpdatesEnabled(true); }); + + // if it matches the current room... add it to the current room as well. + if (QString::compare(room_id, current_room_id, Qt::CaseInsensitive) == 0) { + // Add to the 'local' section + TimelineItem *local_view_item = new TimelineItem(mtx::events::MessageType::Text, + user_id, + body, + true, + room_id, + local_scroll_widget_); + local_view_item->setEventId(event_id); + local_view_item->hide(); + + local_scroll_layout_->addWidget(local_view_item); + + QTimer::singleShot(0, this, [local_view_item, this]() { + local_view_item->show(); + local_view_item->adjustSize(); + }); + } } \ No newline at end of file -- cgit 1.5.1 From 24a649529143dbc1493260a861077217627af657 Mon Sep 17 00:00:00 2001 From: Joseph Donofry Date: Mon, 29 Jul 2019 15:37:21 -0400 Subject: Fix lambda capture issue --- src/dialogs/UserMentions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/dialogs/UserMentions.cpp') diff --git a/src/dialogs/UserMentions.cpp b/src/dialogs/UserMentions.cpp index 4cfcdaca..f0874809 100644 --- a/src/dialogs/UserMentions.cpp +++ b/src/dialogs/UserMentions.cpp @@ -93,7 +93,7 @@ UserMentions::pushItem(const QString &event_id, local_scroll_layout_->addWidget(local_view_item); - QTimer::singleShot(0, this, [local_view_item, this]() { + QTimer::singleShot(0, this, [local_view_item]() { local_view_item->show(); local_view_item->adjustSize(); }); -- cgit 1.5.1 From 3f563e1e6e5e73b0eb50f53cc4568064a0f2f780 Mon Sep 17 00:00:00 2001 From: Joseph Donofry Date: Fri, 9 Aug 2019 23:34:44 -0400 Subject: Cache User Mentions Cache user mentions when they are retrieved from the server. This logic currently isn't being utilized by the UI. Additionally, the app should use a 'since' value to only get mentions newer than those stored in the DB, to avoid excessive web requests. This will be implemented in a future commit. --- CMakeLists.txt | 6 +- src/Cache.cpp | 66 +++++++-- src/Cache.h | 20 ++- src/ChatPage.cpp | 29 ++-- src/ChatPage.h | 6 +- src/UserMentionsWidget.cpp | 309 ------------------------------------------- src/UserMentionsWidget.h | 164 ----------------------- src/dialogs/UserMentions.cpp | 101 -------------- src/dialogs/UserMentions.h | 35 ----- src/popups/UserMentions.cpp | 108 +++++++++++++++ src/popups/UserMentions.h | 40 ++++++ 11 files changed, 246 insertions(+), 638 deletions(-) delete mode 100644 src/UserMentionsWidget.cpp delete mode 100644 src/UserMentionsWidget.h delete mode 100644 src/dialogs/UserMentions.cpp delete mode 100644 src/dialogs/UserMentions.h create mode 100644 src/popups/UserMentions.cpp create mode 100644 src/popups/UserMentions.h (limited to 'src/dialogs/UserMentions.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 09eea071..4d5aff7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,7 +179,6 @@ set(SRC_FILES src/dialogs/LeaveRoom.cpp src/dialogs/Logout.cpp src/dialogs/UserProfile.cpp - src/dialogs/UserMentions.cpp src/dialogs/ReadReceipts.cpp src/dialogs/ReCaptcha.cpp src/dialogs/RoomSettings.cpp @@ -241,13 +240,13 @@ set(SRC_FILES src/popups/SuggestionsPopup.cpp src/popups/PopupItem.cpp src/popups/ReplyPopup.cpp + src/popups/UserMentions.cpp src/TextInputWidget.cpp src/TopRoomBar.cpp src/TrayIcon.cpp src/TypingDisplay.cpp src/Utils.cpp src/UserInfoWidget.cpp - src/UserMentionsWidget.cpp src/UserSettingsPage.cpp src/WelcomePage.cpp src/main.cpp @@ -321,7 +320,6 @@ qt5_wrap_cpp(MOC_HEADERS src/dialogs/MemberList.h src/dialogs/LeaveRoom.h src/dialogs/Logout.h - src/dialogs/UserMentions.h src/dialogs/UserProfile.h src/dialogs/RawMessage.h src/dialogs/ReadReceipts.h @@ -383,12 +381,12 @@ qt5_wrap_cpp(MOC_HEADERS src/popups/SuggestionsPopup.h src/popups/ReplyPopup.h src/popups/PopupItem.h + src/popups/UserMentions.h src/TextInputWidget.h src/TopRoomBar.h src/TrayIcon.h src/TypingDisplay.h src/UserInfoWidget.h - src/UserMentionsWidget.h src/UserSettingsPage.h src/WelcomePage.h ) diff --git a/src/Cache.cpp b/src/Cache.cpp index 9bf3b5b0..5ccf9291 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1232,6 +1232,28 @@ Cache::roomMessages() return msgs; } +std::map +Cache::getTimelineMentions() +{ + // TODO: Should be read-only, but getMentionsDb will attempt to create a DB + // if it doesn't exist, throwing an error. + auto txn = lmdb::txn::begin(env_, nullptr); + + std::map notifs; + + auto room_ids = getRoomIds(txn); + + for (const auto &room_id : room_ids) { + auto roomNotifs = getTimelineMentionsForRoom(txn, room_id); + notifs.emplace(QString::fromStdString(room_id), roomNotifs); + } + + txn.commit(); + + return notifs; +} + + mtx::responses::Timeline Cache::getTimelineMessages(lmdb::txn &txn, const std::string &room_id) { @@ -1934,11 +1956,16 @@ Cache::saveTimelineMessages(lmdb::txn &txn, lmdb::val(obj.dump())); } } + mtx::responses::Notifications -Cache::getTimelineMentions(lmdb::txn &txn, const std::string &room_id) +Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id) { auto db = getMentionsDb(txn, room_id); + if (db.size(txn) == 0) { + return mtx::responses::Notifications{}; + } + mtx::responses::Notifications notif; std::string event_id, msg; @@ -1961,29 +1988,52 @@ Cache::getTimelineMentions(lmdb::txn &txn, const std::string &room_id) return notif; } + +//! Add all notifications containing a user mention to the db. +void +Cache::saveTimelineMentions(const mtx::responses::Notifications &res) +{ + QMap> notifsByRoom; + + // Sort into room-specific 'buckets' + for (const auto ¬if : res.notifications) { + notifsByRoom[notif.room_id].push_back(notif); + } + + auto txn = lmdb::txn::begin(env_); + // Insert the entire set of mentions for each room at a time. + for (const auto &room : notifsByRoom.keys()) { + nhlog::db()->debug("Storing notifications for " + room); + saveTimelineMentions(txn, room, notifsByRoom[room]); + } + + txn.commit(); +} + void Cache::saveTimelineMentions(lmdb::txn &txn, const std::string &room_id, - const mtx::responses::Notifications &res) + const QList &res) { auto db = getMentionsDb(txn, room_id); using namespace mtx::events; using namespace mtx::events::state; - for (const auto &n : res.notifications) { - const auto event_id = utils::event_id(n.event); + int i = 0; + for (const auto ¬if : res) { + nhlog::db()->debug("Storing notification " + std::to_string(i++) + " for room " + room_id); + const auto event_id = utils::event_id(notif.event); // double check that we have the correct room_id... - if (room_id.compare(n.room_id) != 0) - continue; + if (room_id.compare(notif.room_id) != 0) { + return; + } json obj = json::object(); lmdb::dbi_put(txn, db, lmdb::val(event_id), lmdb::val(obj.dump())); } - - txn.commit(); } void diff --git a/src/Cache.h b/src/Cache.h index 5971df66..07ccf790 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -323,6 +323,8 @@ public: std::map roomMessages(); + std::map getTimelineMentions(); + //! Retrieve all the user ids from a room. std::vector roomMembers(const std::string &room_id); @@ -402,13 +404,8 @@ public: //! Check if we have sent a desktop notification for the given event id. bool isNotificationSent(const std::string &event_id); - //! Add a notification containing a user mention to the db. - void saveTimelineMentions(lmdb::txn &txn, - const std::string &room_id, - const mtx::responses::Notifications &res); - //! Get timeline items that a user was mentions in - mtx::responses::Notifications getTimelineMentions(lmdb::txn &txn, - const std::string &room_id); + //! Add all notifications containing a user mention to the db. + void saveTimelineMentions(const mtx::responses::Notifications &res); //! Remove old unused data. void deleteOldMessages(); @@ -478,6 +475,15 @@ private: lmdb::dbi &membersdb, const mtx::responses::InvitedRoom &room); + //! Add a notification containing a user mention to the db. + void saveTimelineMentions(lmdb::txn &txn, + const std::string &room_id, + const QList &res); + + //! Get timeline items that a user was mentions in for a given room + mtx::responses::Notifications getTimelineMentionsForRoom(lmdb::txn &txn, + const std::string &room_id); + QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb); QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index ca18d810..2a02e740 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -35,7 +35,6 @@ #include "TopRoomBar.h" #include "TypingDisplay.h" #include "UserInfoWidget.h" -#include "UserMentionsWidget.h" #include "UserSettingsPage.h" #include "Utils.h" #include "ui/OverlayModal.h" @@ -44,7 +43,7 @@ #include "notifications/Manager.h" #include "dialogs/ReadReceipts.h" -#include "dialogs/UserMentions.h" +#include "popups/UserMentions.h" #include "timeline/TimelineViewManager.h" // TODO: Needs to be updated with an actual secret. @@ -91,7 +90,7 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) connect(sidebarActions_, &SideBarActions::createRoom, this, &ChatPage::createRoom); user_info_widget_ = new UserInfoWidget(sideBar_); - // user_mentions_widget_ = new UserMentionsWidget(top_bar_); + user_mentions_popup_ = new popups::UserMentions(); room_list_ = new RoomList(sideBar_); connect(room_list_, &RoomList::joinRoom, this, &ChatPage::joinRoom); @@ -518,8 +517,17 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom); connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendDesktopNotifications); - connect( - this, &ChatPage::highlightedNotifsRetrieved, this, &ChatPage::showNotificationsDialog); + connect(this, + &ChatPage::highlightedNotifsRetrieved, + this, + [this](const mtx::responses::Notifications ¬if, const QPoint &widgetPos) { + try { + cache::client()->saveTimelineMentions(notif); + } catch (const lmdb::error &e) { + nhlog::db()->error("failed to save mentions: {}", e.what()); + } + showNotificationsDialog(notif, widgetPos); + }); connect(communitiesList_, &CommunitiesList::communityChanged, @@ -558,6 +566,10 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) &ChatPage::initializeEmptyViews, view_manager_, &TimelineViewManager::initWithMessages); + connect(this, + &ChatPage::initializeMentions, + user_mentions_popup_, + &popups::UserMentions::initializeMentions); connect(this, &ChatPage::syncUI, this, [this](const mtx::responses::Rooms &rooms) { try { room_list_->cleanupInvites(cache::client()->invites()); @@ -830,6 +842,7 @@ ChatPage::loadStateFromCache() emit initializeEmptyViews(cache::client()->roomMessages()); emit initializeRoomList(cache::client()->roomInfo()); + emit initializeMentions(cache::client()->getTimelineMentions()); emit syncTags(cache::client()->roomInfo().toStdMap()); cache::client()->calculateRoomReadStatus(); @@ -988,9 +1001,7 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res) void ChatPage::showNotificationsDialog(const mtx::responses::Notifications &res, const QPoint &widgetPos) { - // TODO: This should NOT BE A DIALOG. Make the TimelineView support - // creating a timeline view from notifications (similarly to how it can show history views) - auto notifDialog = new dialogs::UserMentions(); + auto notifDialog = user_mentions_popup_; for (const auto &item : res.notifications) { const auto event_id = QString::fromStdString(utils::event_id(item.event)); @@ -1242,6 +1253,8 @@ ChatPage::sendTypingNotifications() void ChatPage::initialSyncHandler(const mtx::responses::Sync &res, mtx::http::RequestErr err) { + // TODO: Initial Sync should include mentions as well... + if (err) { const auto error = QString::fromStdString(err->matrix_error.error); const auto msg = tr("Please try to login again: %1").arg(error); diff --git a/src/ChatPage.h b/src/ChatPage.h index 3c97ba25..87876a09 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ #include "MatrixClient.h" #include "Utils.h" #include "notifications/Manager.h" +#include "popups/UserMentions.h" class OverlayModal; class QuickSwitcher; @@ -44,7 +46,6 @@ class TimelineViewManager; class TopRoomBar; class TypingDisplay; class UserInfoWidget; -class UserMentionsWidget; class UserSettings; class NotificationsManager; @@ -139,6 +140,7 @@ signals: void initializeRoomList(QMap); void initializeViews(const mtx::responses::Rooms &rooms); void initializeEmptyViews(const std::map &msgs); + void initializeMentions(const std::map ¬ifs); void syncUI(const mtx::responses::Rooms &rooms); void syncRoomlist(const std::map &updates); void syncTags(const std::map &updates); @@ -242,7 +244,7 @@ private: UserInfoWidget *user_info_widget_; - UserMentionsWidget *user_mentions_widget_; + popups::UserMentions *user_mentions_popup_; // Keeps track of the users currently typing on each room. std::map> typingUsers_; diff --git a/src/UserMentionsWidget.cpp b/src/UserMentionsWidget.cpp deleted file mode 100644 index a28db930..00000000 --- a/src/UserMentionsWidget.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include -#include -#include -#include -#include - -#include "MainWindow.h" -#include "UserMentionsWidget.h" -#include "Utils.h" -#include "ui/Ripple.h" -#include "ui/RippleOverlay.h" - -constexpr int MaxUnreadCountDisplayed = 99; - -struct WMetrics -{ - int maxHeight; - int iconSize; - int padding; - int unit; - - int unreadLineWidth; - int unreadLineOffset; - - int inviteBtnX; - int inviteBtnY; -}; - -WMetrics -getWMetrics(const QFont &font) -{ - WMetrics m; - - const int height = QFontMetrics(font).lineSpacing(); - - m.unit = height; - m.maxHeight = std::ceil((double)height * 3.8); - m.iconSize = std::ceil((double)height * 2.8); - m.padding = std::ceil((double)height / 2.0); - m.unreadLineWidth = m.padding - m.padding / 3; - m.unreadLineOffset = m.padding - m.padding / 4; - - m.inviteBtnX = m.iconSize + 2 * m.padding; - m.inviteBtnX = m.iconSize / 2.0 + m.padding + m.padding / 3.0; - - return m; -} - -UserMentionsWidget::UserMentionsWidget(QWidget *parent) - : QWidget(parent) - , isPressed_(false) - , unreadMsgCount_(0) -{ - init(parent); - - QFont f; - f.setPointSizeF(f.pointSizeF()); - - const int fontHeight = QFontMetrics(f).height(); - const int widgetMargin = fontHeight / 3; - const int contentHeight = fontHeight * 3; - - setFixedHeight(contentHeight + widgetMargin); - - topLayout_ = new QHBoxLayout(this); - topLayout_->setSpacing(0); - topLayout_->setMargin(widgetMargin); -} - -void -UserMentionsWidget::init(QWidget *parent) -{ - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - setMouseTracking(true); - setAttribute(Qt::WA_Hover); - - setFixedHeight(getWMetrics(QFont{}).maxHeight); - - QPainterPath path; - path.addRect(0, 0, parent->width(), height()); - - ripple_overlay_ = new RippleOverlay(this); - ripple_overlay_->setClipPath(path); - ripple_overlay_->setClipping(true); - - unreadCountFont_.setPointSizeF(unreadCountFont_.pointSizeF() * 0.8); - unreadCountFont_.setBold(true); - - bubbleDiameter_ = QFontMetrics(unreadCountFont_).averageCharWidth() * 3; -} - -// void -// UserMentionsWidget::resizeEvent(QResizeEvent *event) -// { -// Q_UNUSED(event); - -// const auto sz = utils::calculateSidebarSizes(QFont{}); - -// if (width() <= sz.small) { -// topLayout_->setContentsMargins(0, 0, logoutButtonSize_, 0); - -// } else { -// topLayout_->setMargin(5); -// } - -// QWidget::resizeEvent(event); -// } - -void -UserMentionsWidget::setPressedState(bool state) -{ - if (isPressed_ != state) { - isPressed_ = state; - update(); - } -} - -void -UserMentionsWidget::resizeEvent(QResizeEvent *) -{ - // Update ripple's clipping path. - QPainterPath path; - path.addRect(0, 0, width(), height()); - - const auto sidebarSizes = utils::calculateSidebarSizes(QFont{}); - - if (width() > sidebarSizes.small) - setToolTip(""); - else - setToolTip(""); - - ripple_overlay_->setClipPath(path); - ripple_overlay_->setClipping(true); -} - -void -UserMentionsWidget::mousePressEvent(QMouseEvent *event) -{ - if (event->buttons() == Qt::RightButton) { - QWidget::mousePressEvent(event); - return; - } - - emit clicked(); - - setPressedState(true); - - // Ripple on mouse position by default. - QPoint pos = event->pos(); - qreal radiusEndValue = static_cast(width()) / 3; - - Ripple *ripple = new Ripple(pos); - - ripple->setRadiusEndValue(radiusEndValue); - ripple->setOpacityStartValue(0.15); - ripple->setColor(QColor("white")); - ripple->radiusAnimation()->setDuration(200); - ripple->opacityAnimation()->setDuration(400); - - ripple_overlay_->addRipple(ripple); -} - -void -UserMentionsWidget::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); - - QPainter p(this); - p.setRenderHint(QPainter::TextAntialiasing); - p.setRenderHint(QPainter::SmoothPixmapTransform); - p.setRenderHint(QPainter::Antialiasing); - - auto wm = getWMetrics(QFont{}); - - QPen titlePen(titleColor_); - QPen subtitlePen(subtitleColor_); - - QFontMetrics metrics(QFont{}); - - if (isPressed_) { - p.fillRect(rect(), highlightedBackgroundColor_); - titlePen.setColor(highlightedTitleColor_); - subtitlePen.setColor(highlightedSubtitleColor_); - } else if (underMouse()) { - p.fillRect(rect(), hoverBackgroundColor_); - titlePen.setColor(hoverTitleColor_); - subtitlePen.setColor(hoverSubtitleColor_); - } else { - p.fillRect(rect(), backgroundColor_); - titlePen.setColor(titleColor_); - subtitlePen.setColor(subtitleColor_); - } - - // Description line with the default font. - int bottom_y = wm.maxHeight - wm.padding - metrics.ascent() / 2; - - const auto sidebarSizes = utils::calculateSidebarSizes(QFont{}); - - if (width() > sidebarSizes.small) { - QFont headingFont; - headingFont.setWeight(QFont::Medium); - p.setFont(headingFont); - p.setPen(titlePen); - - QFont tsFont; - tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9); -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) - const int msgStampWidth = QFontMetrics(tsFont).width("timestamp") + 4; -#else - const int msgStampWidth = QFontMetrics(tsFont).horizontalAdvance("timestamp") + 4; -#endif - // We use the full width of the widget if there is no unread msg bubble. - // const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0; - - // Name line. - QFontMetrics fontNameMetrics(headingFont); - int top_y = 2 * wm.padding + fontNameMetrics.ascent() / 2; - - const auto name = metrics.elidedText( - "Mentions", - Qt::ElideRight, - (width() - wm.iconSize - 2 * wm.padding - msgStampWidth) * 0.8); - p.drawText(QPoint(2 * wm.padding + wm.iconSize, top_y), name); - - p.setFont(QFont{}); - p.setPen(subtitlePen); - - // The limit is the space between the end of the avatar and the start of the - // timestamp. - int usernameLimit = - std::max(0, width() - 3 * wm.padding - msgStampWidth - wm.iconSize - 20); - auto userName = - metrics.elidedText("Show Mentioned Messages", Qt::ElideRight, usernameLimit); - - p.setFont(QFont{}); - p.drawText(QPoint(2 * wm.padding + wm.iconSize, bottom_y), userName); - - // We show the last message timestamp. - p.save(); - if (isPressed_) { - p.setPen(QPen(highlightedTimestampColor_)); - } else if (underMouse()) { - p.setPen(QPen(hoverTimestampColor_)); - } else { - p.setPen(QPen(timestampColor_)); - } - - // p.setFont(tsFont); - // p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y), "timestamp"); - p.restore(); - } - - p.setPen(Qt::NoPen); - - if (unreadMsgCount_ > 0) { - QBrush brush; - brush.setStyle(Qt::SolidPattern); - - brush.setColor(mentionedColor()); - - if (isPressed_) - brush.setColor(bubbleFgColor()); - - p.setBrush(brush); - p.setPen(Qt::NoPen); - p.setFont(unreadCountFont_); - - // Extra space on the x-axis to accomodate the extra character space - // inside the bubble. - const int x_width = unreadMsgCount_ > MaxUnreadCountDisplayed - ? QFontMetrics(p.font()).averageCharWidth() - : 0; - - QRectF r(width() - bubbleDiameter_ - wm.padding - x_width, - bottom_y - bubbleDiameter_ / 2 - 5, - bubbleDiameter_ + x_width, - bubbleDiameter_); - - if (width() == sidebarSizes.small) - r = QRectF(width() - bubbleDiameter_ - 5, - height() - bubbleDiameter_ - 5, - bubbleDiameter_ + x_width, - bubbleDiameter_); - - p.setPen(Qt::NoPen); - p.drawEllipse(r); - - p.setPen(QPen(bubbleFgColor())); - - if (isPressed_) - p.setPen(QPen(bubbleBgColor())); - - auto countTxt = unreadMsgCount_ > MaxUnreadCountDisplayed - ? QString("99+") - : QString::number(unreadMsgCount_); - - p.setBrush(Qt::NoBrush); - p.drawText(r.translated(0, -0.5), Qt::AlignCenter, countTxt); - } - - if (!isPressed_ && hasUnreadMessages_) { - QPen pen; - pen.setWidth(wm.unreadLineWidth); - pen.setColor(highlightedBackgroundColor_); - - p.setPen(pen); - p.drawLine(0, wm.unreadLineOffset, 0, height() - wm.unreadLineOffset); - } -} \ No newline at end of file diff --git a/src/UserMentionsWidget.h b/src/UserMentionsWidget.h deleted file mode 100644 index 179f0026..00000000 --- a/src/UserMentionsWidget.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class FlatButton; -class RippleOverlay; - -class UserMentionsWidget : public QWidget -{ - Q_OBJECT - - Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor) - - Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE - setHighlightedBackgroundColor) - Q_PROPERTY( - QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor) - Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor) - - Q_PROPERTY(QColor avatarBgColor READ avatarBgColor WRITE setAvatarBgColor) - Q_PROPERTY(QColor avatarFgColor READ avatarFgColor WRITE setAvatarFgColor) - - Q_PROPERTY(QColor bubbleBgColor READ bubbleBgColor WRITE setBubbleBgColor) - Q_PROPERTY(QColor bubbleFgColor READ bubbleFgColor WRITE setBubbleFgColor) - - Q_PROPERTY(QColor titleColor READ titleColor WRITE setTitleColor) - Q_PROPERTY(QColor subtitleColor READ subtitleColor WRITE setSubtitleColor) - - Q_PROPERTY(QColor timestampColor READ timestampColor WRITE setTimestampColor) - Q_PROPERTY(QColor highlightedTimestampColor READ highlightedTimestampColor WRITE - setHighlightedTimestampColor) - Q_PROPERTY(QColor hoverTimestampColor READ hoverTimestampColor WRITE setHoverTimestampColor) - - Q_PROPERTY( - QColor highlightedTitleColor READ highlightedTitleColor WRITE setHighlightedTitleColor) - Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE - setHighlightedSubtitleColor) - - Q_PROPERTY(QColor hoverTitleColor READ hoverTitleColor WRITE setHoverTitleColor) - Q_PROPERTY(QColor hoverSubtitleColor READ hoverSubtitleColor WRITE setHoverSubtitleColor) - - Q_PROPERTY(QColor mentionedColor READ mentionedColor WRITE setMentionedColor) - Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor) - Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor) - -public: - UserMentionsWidget(QWidget *parent = 0); - - void updateUnreadMessageCount(int count); - void clearUnreadMessageCount() { updateUnreadMessageCount(0); }; - bool isPressed() const { return isPressed_; } - int unreadMessageCount() const { return unreadMsgCount_; } - QColor borderColor() const { return borderColor_; } - void setBorderColor(QColor &color) { borderColor_ = color; } - QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; } - QColor hoverBackgroundColor() const { return hoverBackgroundColor_; } - QColor hoverTitleColor() const { return hoverTitleColor_; } - QColor hoverSubtitleColor() const { return hoverSubtitleColor_; } - QColor hoverTimestampColor() const { return hoverTimestampColor_; } - QColor backgroundColor() const { return backgroundColor_; } - QColor avatarBgColor() const { return avatarBgColor_; } - QColor avatarFgColor() const { return avatarFgColor_; } - - QColor highlightedTitleColor() const { return highlightedTitleColor_; } - QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; } - QColor highlightedTimestampColor() const { return highlightedTimestampColor_; } - - QColor titleColor() const { return titleColor_; } - QColor subtitleColor() const { return subtitleColor_; } - QColor timestampColor() const { return timestampColor_; } - QColor btnColor() const { return btnColor_; } - QColor btnTextColor() const { return btnTextColor_; } - - QColor bubbleFgColor() const { return bubbleFgColor_; } - QColor bubbleBgColor() const { return bubbleBgColor_; } - QColor mentionedColor() const { return mentionedFontColor_; } - - void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; } - void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; } - void setHoverSubtitleColor(QColor &color) { hoverSubtitleColor_ = color; } - void setHoverTitleColor(QColor &color) { hoverTitleColor_ = color; } - void setHoverTimestampColor(QColor &color) { hoverTimestampColor_ = color; } - void setBackgroundColor(QColor &color) { backgroundColor_ = color; } - void setTimestampColor(QColor &color) { timestampColor_ = color; } - void setAvatarFgColor(QColor &color) { avatarFgColor_ = color; } - void setAvatarBgColor(QColor &color) { avatarBgColor_ = color; } - - void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; } - void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; } - void setHighlightedTimestampColor(QColor &color) { highlightedTimestampColor_ = color; } - - void setTitleColor(QColor &color) { titleColor_ = color; } - void setSubtitleColor(QColor &color) { subtitleColor_ = color; } - - void setBtnColor(QColor &color) { btnColor_ = color; } - void setBtnTextColor(QColor &color) { btnTextColor_ = color; } - - void setBubbleFgColor(QColor &color) { bubbleFgColor_ = color; } - void setBubbleBgColor(QColor &color) { bubbleBgColor_ = color; } - void setMentionedColor(QColor &color) { mentionedFontColor_ = color; } - -signals: - void clicked(); - -public slots: - void setPressedState(bool state); - -protected: - void mousePressEvent(QMouseEvent *event) override; - void paintEvent(QPaintEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - -private: - void init(QWidget *parent); - - RippleOverlay *ripple_overlay_; - - bool isPressed_ = false; - - bool hasUnreadMessages_ = true; - - int unreadMsgCount_ = 0; - - QHBoxLayout *topLayout_; - - QColor borderColor_; - QColor highlightedBackgroundColor_; - QColor hoverBackgroundColor_; - QColor backgroundColor_; - - QColor highlightedTitleColor_; - QColor highlightedSubtitleColor_; - - QColor titleColor_; - QColor subtitleColor_; - - QColor hoverTitleColor_; - QColor hoverSubtitleColor_; - - QColor btnColor_; - QColor btnTextColor_; - - QRectF acceptBtnRegion_; - QRectF declineBtnRegion_; - - // Fonts - QColor mentionedFontColor_; - QFont unreadCountFont_; - int bubbleDiameter_; - - QColor timestampColor_; - QColor highlightedTimestampColor_; - QColor hoverTimestampColor_; - - QColor avatarBgColor_; - QColor avatarFgColor_; - - QColor bubbleBgColor_; - QColor bubbleFgColor_; -}; \ No newline at end of file diff --git a/src/dialogs/UserMentions.cpp b/src/dialogs/UserMentions.cpp deleted file mode 100644 index f0874809..00000000 --- a/src/dialogs/UserMentions.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include - -#include "UserMentions.h" -#include "timeline/TimelineItem.h" - -using namespace dialogs; - -UserMentions::UserMentions(QWidget *parent) - : QWidget{parent} -{ - tab_layout_ = new QTabWidget(this); - - top_layout_ = new QVBoxLayout(this); - top_layout_->setSpacing(0); - top_layout_->setMargin(0); - - local_scroll_area_ = new QScrollArea(this); - local_scroll_area_->setWidgetResizable(true); - local_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - local_scroll_widget_ = new QWidget(this); - local_scroll_widget_->setObjectName("local_scroll_widget"); - - all_scroll_area_ = new QScrollArea(this); - all_scroll_area_->setWidgetResizable(true); - all_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - all_scroll_widget_ = new QWidget(this); - all_scroll_widget_->setObjectName("all_scroll_widget"); - - // Height of the typing display. - QFont f; - f.setPointSizeF(f.pointSizeF() * 0.9); - const int bottomMargin = QFontMetrics(f).height() + 6; - - local_scroll_layout_ = new QVBoxLayout(local_scroll_widget_); - local_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); - local_scroll_layout_->setSpacing(0); - local_scroll_layout_->setObjectName("localcrollarea"); - - all_scroll_layout_ = new QVBoxLayout(all_scroll_widget_); - all_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); - all_scroll_layout_->setSpacing(0); - all_scroll_layout_->setObjectName("allcrollarea"); - - local_scroll_area_->setWidget(local_scroll_widget_); - local_scroll_area_->setAlignment(Qt::AlignBottom); - - all_scroll_area_->setWidget(all_scroll_widget_); - all_scroll_area_->setAlignment(Qt::AlignBottom); - - tab_layout_->addTab(local_scroll_area_, tr("This Room")); - tab_layout_->addTab(all_scroll_area_, tr("All Rooms")); - top_layout_->addWidget(tab_layout_); - - setLayout(top_layout_); -} - -void -UserMentions::pushItem(const QString &event_id, - const QString &user_id, - const QString &body, - const QString &room_id, - const QString ¤t_room_id) -{ - setUpdatesEnabled(false); - - // Add to the 'all' section - TimelineItem *view_item = new TimelineItem( - mtx::events::MessageType::Text, user_id, body, true, room_id, all_scroll_widget_); - view_item->setEventId(event_id); - view_item->hide(); - - all_scroll_layout_->addWidget(view_item); - QTimer::singleShot(0, this, [view_item, this]() { - view_item->show(); - view_item->adjustSize(); - setUpdatesEnabled(true); - }); - - // if it matches the current room... add it to the current room as well. - if (QString::compare(room_id, current_room_id, Qt::CaseInsensitive) == 0) { - // Add to the 'local' section - TimelineItem *local_view_item = new TimelineItem(mtx::events::MessageType::Text, - user_id, - body, - true, - room_id, - local_scroll_widget_); - local_view_item->setEventId(event_id); - local_view_item->hide(); - - local_scroll_layout_->addWidget(local_view_item); - - QTimer::singleShot(0, this, [local_view_item]() { - local_view_item->show(); - local_view_item->adjustSize(); - }); - } -} \ No newline at end of file diff --git a/src/dialogs/UserMentions.h b/src/dialogs/UserMentions.h deleted file mode 100644 index 9b43dcfd..00000000 --- a/src/dialogs/UserMentions.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace dialogs { - -class UserMentions : public QWidget -{ - Q_OBJECT -public: - UserMentions(QWidget *parent = nullptr); - void pushItem(const QString &event_id, - const QString &user_id, - const QString &body, - const QString &room_id, - const QString ¤t_room_id); - -private: - QTabWidget *tab_layout_; - QVBoxLayout *top_layout_; - QVBoxLayout *local_scroll_layout_; - QVBoxLayout *all_scroll_layout_; - - QScrollArea *local_scroll_area_; - QWidget *local_scroll_widget_; - - QScrollArea *all_scroll_area_; - QWidget *all_scroll_widget_; -}; - -} \ No newline at end of file diff --git a/src/popups/UserMentions.cpp b/src/popups/UserMentions.cpp new file mode 100644 index 00000000..77e5260e --- /dev/null +++ b/src/popups/UserMentions.cpp @@ -0,0 +1,108 @@ +#include +#include + +#include "UserMentions.h" +#include "timeline/TimelineItem.h" + +using namespace popups; + +UserMentions::UserMentions(QWidget *parent) + : QWidget{parent} +{ + tab_layout_ = new QTabWidget(this); + + top_layout_ = new QVBoxLayout(this); + top_layout_->setSpacing(0); + top_layout_->setMargin(0); + + local_scroll_area_ = new QScrollArea(this); + local_scroll_area_->setWidgetResizable(true); + local_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + local_scroll_widget_ = new QWidget(this); + local_scroll_widget_->setObjectName("local_scroll_widget"); + + all_scroll_area_ = new QScrollArea(this); + all_scroll_area_->setWidgetResizable(true); + all_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + all_scroll_widget_ = new QWidget(this); + all_scroll_widget_->setObjectName("all_scroll_widget"); + + // Height of the typing display. + QFont f; + f.setPointSizeF(f.pointSizeF() * 0.9); + const int bottomMargin = QFontMetrics(f).height() + 6; + + local_scroll_layout_ = new QVBoxLayout(local_scroll_widget_); + local_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); + local_scroll_layout_->setSpacing(0); + local_scroll_layout_->setObjectName("localcrollarea"); + + all_scroll_layout_ = new QVBoxLayout(all_scroll_widget_); + all_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin); + all_scroll_layout_->setSpacing(0); + all_scroll_layout_->setObjectName("allcrollarea"); + + local_scroll_area_->setWidget(local_scroll_widget_); + local_scroll_area_->setAlignment(Qt::AlignBottom); + + all_scroll_area_->setWidget(all_scroll_widget_); + all_scroll_area_->setAlignment(Qt::AlignBottom); + + tab_layout_->addTab(local_scroll_area_, tr("This Room")); + tab_layout_->addTab(all_scroll_area_, tr("All Rooms")); + top_layout_->addWidget(tab_layout_); + + setLayout(top_layout_); +} + +void +UserMentions::initializeMentions(const std::map ¬ifs) +{ + Q_UNUSED(notifs); + // Very TODO: +} + +void +UserMentions::pushItem(const QString &event_id, + const QString &user_id, + const QString &body, + const QString &room_id, + const QString ¤t_room_id) +{ + setUpdatesEnabled(false); + + // Add to the 'all' section + TimelineItem *view_item = new TimelineItem( + mtx::events::MessageType::Text, user_id, body, true, room_id, all_scroll_widget_); + view_item->setEventId(event_id); + view_item->hide(); + + all_scroll_layout_->addWidget(view_item); + QTimer::singleShot(0, this, [view_item, this]() { + view_item->show(); + view_item->adjustSize(); + setUpdatesEnabled(true); + }); + + // if it matches the current room... add it to the current room as well. + if (QString::compare(room_id, current_room_id, Qt::CaseInsensitive) == 0) { + // Add to the 'local' section + TimelineItem *local_view_item = new TimelineItem(mtx::events::MessageType::Text, + user_id, + body, + true, + room_id, + local_scroll_widget_); + local_view_item->setEventId(event_id); + local_view_item->hide(); + + local_scroll_layout_->addWidget(local_view_item); + + QTimer::singleShot(0, this, [local_view_item]() { + local_view_item->show(); + local_view_item->adjustSize(); + }); + } +} \ No newline at end of file diff --git a/src/popups/UserMentions.h b/src/popups/UserMentions.h new file mode 100644 index 00000000..5dc475bf --- /dev/null +++ b/src/popups/UserMentions.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +namespace popups { + +class UserMentions : public QWidget +{ + Q_OBJECT +public: + UserMentions(QWidget *parent = nullptr); + void pushItem(const QString &event_id, + const QString &user_id, + const QString &body, + const QString &room_id, + const QString ¤t_room_id); + + void initializeMentions(const std::map ¬ifs); + +private: + QTabWidget *tab_layout_; + QVBoxLayout *top_layout_; + QVBoxLayout *local_scroll_layout_; + QVBoxLayout *all_scroll_layout_; + + QScrollArea *local_scroll_area_; + QWidget *local_scroll_widget_; + + QScrollArea *all_scroll_area_; + QWidget *all_scroll_widget_; +}; + +} \ No newline at end of file -- cgit 1.5.1