diff --git a/src/popups/PopupItem.cpp b/src/popups/PopupItem.cpp
new file mode 100644
index 00000000..db97e4a3
--- /dev/null
+++ b/src/popups/PopupItem.cpp
@@ -0,0 +1,141 @@
+#include <QPaintEvent>
+#include <QPainter>
+#include <QStyleOption>
+
+#include "../Utils.h"
+#include "../ui/Avatar.h"
+#include "PopupItem.h"
+
+constexpr int PopupHMargin = 4;
+constexpr int PopupItemMargin = 3;
+
+PopupItem::PopupItem(QWidget *parent)
+ : QWidget(parent)
+ , avatar_{new Avatar(this, conf::popup::avatar)}
+ , hovering_{false}
+{
+ setMouseTracking(true);
+ setAttribute(Qt::WA_Hover);
+
+ topLayout_ = new QHBoxLayout(this);
+ topLayout_->setContentsMargins(
+ PopupHMargin, PopupItemMargin, PopupHMargin, PopupItemMargin);
+
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+}
+
+void
+PopupItem::paintEvent(QPaintEvent *)
+{
+ QStyleOption opt;
+ opt.init(this);
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+
+ if (underMouse() || hovering_)
+ p.fillRect(rect(), hoverColor_);
+}
+
+UserItem::UserItem(QWidget *parent)
+ : PopupItem(parent)
+{
+ userName_ = new QLabel("Placeholder", this);
+ avatar_->setLetter("P");
+ topLayout_->addWidget(avatar_);
+ topLayout_->addWidget(userName_, 1);
+}
+
+UserItem::UserItem(QWidget *parent, const QString &user_id)
+ : PopupItem(parent)
+ , userId_{user_id}
+{
+ auto displayName = cache::displayName(ChatPage::instance()->currentRoom(), userId_);
+
+ avatar_->setLetter(utils::firstChar(displayName));
+
+ // If it's a matrix id we use the second letter.
+ if (displayName.size() > 1 && displayName.at(0) == '@')
+ avatar_->setLetter(QChar(displayName.at(1)));
+
+ userName_ = new QLabel(displayName, this);
+
+ topLayout_->addWidget(avatar_);
+ topLayout_->addWidget(userName_, 1);
+
+ resolveAvatar(user_id);
+}
+
+void
+UserItem::updateItem(const QString &user_id)
+{
+ userId_ = user_id;
+
+ auto displayName = cache::displayName(ChatPage::instance()->currentRoom(), userId_);
+
+ // If it's a matrix id we use the second letter.
+ if (displayName.size() > 1 && displayName.at(0) == '@')
+ avatar_->setLetter(QChar(displayName.at(1)));
+ else
+ avatar_->setLetter(utils::firstChar(displayName));
+
+ userName_->setText(displayName);
+ resolveAvatar(user_id);
+}
+
+void
+UserItem::resolveAvatar(const QString &user_id)
+{
+ avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
+}
+
+void
+UserItem::mousePressEvent(QMouseEvent *event)
+{
+ if (event->buttons() != Qt::RightButton)
+ emit clicked(
+ cache::displayName(ChatPage::instance()->currentRoom(), selectedText()));
+
+ QWidget::mousePressEvent(event);
+}
+
+RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
+ : PopupItem(parent)
+ , roomId_{QString::fromStdString(res.room_id)}
+{
+ auto name = QFontMetrics(QFont()).elidedText(
+ QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10);
+
+ avatar_->setLetter(utils::firstChar(name));
+
+ roomName_ = new QLabel(name, this);
+ roomName_->setMargin(0);
+
+ topLayout_->addWidget(avatar_);
+ topLayout_->addWidget(roomName_, 1);
+
+ avatar_->setImage(QString::fromStdString(res.info.avatar_url));
+}
+
+void
+RoomItem::updateItem(const RoomSearchResult &result)
+{
+ roomId_ = QString::fromStdString(std::move(result.room_id));
+
+ auto name =
+ QFontMetrics(QFont()).elidedText(QString::fromStdString(std::move(result.info.name)),
+ Qt::ElideRight,
+ parentWidget()->width() - 10);
+
+ roomName_->setText(name);
+
+ avatar_->setImage(QString::fromStdString(result.info.avatar_url));
+}
+
+void
+RoomItem::mousePressEvent(QMouseEvent *event)
+{
+ if (event->buttons() != Qt::RightButton)
+ emit clicked(selectedText());
+
+ QWidget::mousePressEvent(event);
+}
diff --git a/src/popups/PopupItem.h b/src/popups/PopupItem.h
new file mode 100644
index 00000000..7a710fdb
--- /dev/null
+++ b/src/popups/PopupItem.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPoint>
+#include <QWidget>
+
+#include "../AvatarProvider.h"
+#include "../ChatPage.h"
+
+class Avatar;
+struct SearchResult;
+
+class PopupItem : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor)
+ Q_PROPERTY(bool hovering READ hovering WRITE setHovering)
+
+public:
+ PopupItem(QWidget *parent);
+
+ QString selectedText() const { return QString(); }
+ QColor hoverColor() const { return hoverColor_; }
+ void setHoverColor(QColor &color) { hoverColor_ = color; }
+
+ bool hovering() const { return hovering_; }
+ void setHovering(const bool hover) { hovering_ = hover; };
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+
+signals:
+ void clicked(const QString &text);
+
+protected:
+ QHBoxLayout *topLayout_;
+ Avatar *avatar_;
+ QColor hoverColor_;
+
+ //! Set if the item is currently being
+ //! hovered during tab completion (cycling).
+ bool hovering_;
+};
+
+class UserItem : public PopupItem
+{
+ Q_OBJECT
+
+public:
+ UserItem(QWidget *parent);
+ UserItem(QWidget *parent, const QString &user_id);
+ QString selectedText() const { return userId_; }
+ void updateItem(const QString &user_id);
+
+protected:
+ void mousePressEvent(QMouseEvent *event) override;
+
+private:
+ void resolveAvatar(const QString &user_id);
+
+ QLabel *userName_;
+ QString userId_;
+};
+
+class RoomItem : public PopupItem
+{
+ Q_OBJECT
+
+public:
+ RoomItem(QWidget *parent, const RoomSearchResult &res);
+ QString selectedText() const { return roomId_; }
+ void updateItem(const RoomSearchResult &res);
+
+protected:
+ void mousePressEvent(QMouseEvent *event) override;
+
+private:
+ QLabel *roomName_;
+ QString roomId_;
+ RoomSearchResult info_;
+};
diff --git a/src/popups/ReplyPopup.cpp b/src/popups/ReplyPopup.cpp
new file mode 100644
index 00000000..5058c039
--- /dev/null
+++ b/src/popups/ReplyPopup.cpp
@@ -0,0 +1,103 @@
+#include <QLabel>
+#include <QPaintEvent>
+#include <QPainter>
+#include <QStyleOption>
+
+#include "../Config.h"
+#include "../Utils.h"
+#include "../ui/Avatar.h"
+#include "../ui/DropShadow.h"
+#include "../ui/TextLabel.h"
+#include "PopupItem.h"
+#include "ReplyPopup.h"
+
+ReplyPopup::ReplyPopup(QWidget *parent)
+ : QWidget(parent)
+ , userItem_{nullptr}
+ , msgLabel_{nullptr}
+ , eventLabel_{nullptr}
+{
+ setAttribute(Qt::WA_ShowWithoutActivating, true);
+ setWindowFlags(Qt::ToolTip | Qt::NoDropShadowWindowHint);
+
+ mainLayout_ = new QVBoxLayout(this);
+ mainLayout_->setMargin(0);
+ mainLayout_->setSpacing(0);
+
+ topLayout_ = new QHBoxLayout();
+ topLayout_->setSpacing(0);
+ topLayout_->setContentsMargins(13, 1, 13, 0);
+
+ userItem_ = new UserItem(this);
+ connect(userItem_, &UserItem::clicked, this, &ReplyPopup::userSelected);
+ topLayout_->addWidget(userItem_);
+
+ buttonLayout_ = new QHBoxLayout();
+ buttonLayout_->setSpacing(0);
+ buttonLayout_->setMargin(0);
+
+ topLayout_->addLayout(buttonLayout_);
+ QFont f;
+ f.setPointSizeF(f.pointSizeF());
+ const int fontHeight = QFontMetrics(f).height();
+ buttonSize_ = std::min(fontHeight, 20);
+
+ closeBtn_ = new FlatButton(this);
+ closeBtn_->setToolTip(tr("Logout"));
+ closeBtn_->setCornerRadius(buttonSize_ / 4);
+ closeBtn_->setText("X");
+
+ QIcon icon;
+ icon.addFile(":/icons/icons/ui/remove-symbol.png");
+
+ closeBtn_->setIcon(icon);
+ closeBtn_->setIconSize(QSize(buttonSize_, buttonSize_));
+ connect(closeBtn_, &FlatButton::clicked, this, [this]() { emit cancel(); });
+
+ buttonLayout_->addWidget(closeBtn_);
+
+ topLayout_->addLayout(buttonLayout_);
+
+ mainLayout_->addLayout(topLayout_);
+ msgLabel_ = new TextLabel(this);
+ msgLabel_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction);
+ mainLayout_->addWidget(msgLabel_);
+ eventLabel_ = new QLabel(this);
+ mainLayout_->addWidget(eventLabel_);
+
+ setLayout(mainLayout_);
+}
+
+void
+ReplyPopup::setReplyContent(const RelatedInfo &related)
+{
+ // Update the current widget with the new data.
+ userItem_->updateItem(related.quoted_user);
+
+ msgLabel_->setText(utils::getFormattedQuoteBody(related, "")
+ .replace("<mx-reply>", "")
+ .replace("</mx-reply>", ""));
+
+ // eventLabel_->setText(srcEvent);
+
+ adjustSize();
+}
+
+void
+ReplyPopup::paintEvent(QPaintEvent *)
+{
+ QStyleOption opt;
+ opt.init(this);
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+}
+
+void
+ReplyPopup::mousePressEvent(QMouseEvent *event)
+{
+ if (event->buttons() != Qt::RightButton) {
+ emit clicked(eventLabel_->text());
+ }
+
+ QWidget::mousePressEvent(event);
+}
diff --git a/src/popups/ReplyPopup.h b/src/popups/ReplyPopup.h
new file mode 100644
index 00000000..1fa3bb83
--- /dev/null
+++ b/src/popups/ReplyPopup.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QWidget>
+
+#include "../ui/FlatButton.h"
+#include "../ui/TextLabel.h"
+
+struct RelatedInfo;
+class UserItem;
+
+class ReplyPopup : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ReplyPopup(QWidget *parent = nullptr);
+
+public slots:
+ void setReplyContent(const RelatedInfo &related);
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+
+signals:
+ void userSelected(const QString &user);
+ void clicked(const QString &text);
+ void cancel();
+
+private:
+ QHBoxLayout *topLayout_;
+ QVBoxLayout *mainLayout_;
+ QHBoxLayout *buttonLayout_;
+
+ UserItem *userItem_;
+ FlatButton *closeBtn_;
+ TextLabel *msgLabel_;
+ QLabel *eventLabel_;
+
+ int buttonSize_;
+};
diff --git a/src/popups/SuggestionsPopup.cpp b/src/popups/SuggestionsPopup.cpp
new file mode 100644
index 00000000..8f355b38
--- /dev/null
+++ b/src/popups/SuggestionsPopup.cpp
@@ -0,0 +1,156 @@
+#include <QPaintEvent>
+#include <QPainter>
+#include <QStyleOption>
+
+#include "../Config.h"
+#include "../Utils.h"
+#include "../ui/Avatar.h"
+#include "../ui/DropShadow.h"
+#include "SuggestionsPopup.h"
+
+SuggestionsPopup::SuggestionsPopup(QWidget *parent)
+ : QWidget(parent)
+{
+ setAttribute(Qt::WA_ShowWithoutActivating, true);
+ setWindowFlags(Qt::ToolTip | Qt::NoDropShadowWindowHint);
+
+ layout_ = new QVBoxLayout(this);
+ layout_->setMargin(0);
+ layout_->setSpacing(0);
+}
+
+void
+SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
+{
+ if (rooms.empty()) {
+ hide();
+ return;
+ }
+
+ const size_t layoutCount = layout_->count();
+ const size_t roomCount = rooms.size();
+
+ // Remove the extra widgets from the layout.
+ if (roomCount < layoutCount)
+ removeLayoutItemsAfter(roomCount - 1);
+
+ for (size_t i = 0; i < roomCount; ++i) {
+ auto item = layout_->itemAt(i);
+
+ // Create a new widget if there isn't already one in that
+ // layout position.
+ if (!item) {
+ auto room = new RoomItem(this, rooms.at(i));
+ connect(room, &RoomItem::clicked, this, &SuggestionsPopup::itemSelected);
+ layout_->addWidget(room);
+ } else {
+ // Update the current widget with the new data.
+ auto room = qobject_cast<RoomItem *>(item->widget());
+ if (room)
+ room->updateItem(rooms.at(i));
+ }
+ }
+
+ resetSelection();
+ adjustSize();
+
+ resize(geometry().width(), 40 * rooms.size());
+
+ selectNextSuggestion();
+}
+
+void
+SuggestionsPopup::addUsers(const std::vector<SearchResult> &users)
+{
+ if (users.empty()) {
+ hide();
+ return;
+ }
+
+ const size_t layoutCount = layout_->count();
+ const size_t userCount = users.size();
+
+ // Remove the extra widgets from the layout.
+ if (userCount < layoutCount)
+ removeLayoutItemsAfter(userCount - 1);
+
+ for (size_t i = 0; i < userCount; ++i) {
+ auto item = layout_->itemAt(i);
+
+ // Create a new widget if there isn't already one in that
+ // layout position.
+ if (!item) {
+ auto user = new UserItem(this, users.at(i).user_id);
+ connect(user, &UserItem::clicked, this, &SuggestionsPopup::itemSelected);
+ layout_->addWidget(user);
+ } else {
+ // Update the current widget with the new data.
+ auto userWidget = qobject_cast<UserItem *>(item->widget());
+ if (userWidget)
+ userWidget->updateItem(users.at(i).user_id);
+ }
+ }
+
+ resetSelection();
+ adjustSize();
+
+ selectNextSuggestion();
+}
+
+void
+SuggestionsPopup::hoverSelection()
+{
+ resetHovering();
+ setHovering(selectedItem_);
+ update();
+}
+
+void
+SuggestionsPopup::selectNextSuggestion()
+{
+ selectedItem_++;
+ if (selectedItem_ >= layout_->count())
+ selectFirstItem();
+
+ hoverSelection();
+}
+
+void
+SuggestionsPopup::selectPreviousSuggestion()
+{
+ selectedItem_--;
+ if (selectedItem_ < 0)
+ selectLastItem();
+
+ hoverSelection();
+}
+
+void
+SuggestionsPopup::resetHovering()
+{
+ for (int i = 0; i < layout_->count(); ++i) {
+ const auto item = qobject_cast<PopupItem *>(layout_->itemAt(i)->widget());
+
+ if (item)
+ item->setHovering(false);
+ }
+}
+
+void
+SuggestionsPopup::setHovering(int pos)
+{
+ const auto &item = layout_->itemAt(pos);
+ const auto &widget = qobject_cast<PopupItem *>(item->widget());
+
+ if (widget)
+ widget->setHovering(true);
+}
+
+void
+SuggestionsPopup::paintEvent(QPaintEvent *)
+{
+ QStyleOption opt;
+ opt.init(this);
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+}
diff --git a/src/popups/SuggestionsPopup.h b/src/popups/SuggestionsPopup.h
new file mode 100644
index 00000000..63c44538
--- /dev/null
+++ b/src/popups/SuggestionsPopup.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPoint>
+#include <QWidget>
+
+#include "CacheStructs.h"
+#include "ChatPage.h"
+#include "PopupItem.h"
+
+class SuggestionsPopup : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit SuggestionsPopup(QWidget *parent = nullptr);
+
+ template<class Item>
+ void selectHoveredSuggestion()
+ {
+ const auto item = layout_->itemAt(selectedItem_);
+ if (!item)
+ return;
+
+ const auto &widget = qobject_cast<Item *>(item->widget());
+ emit itemSelected(
+ cache::displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
+
+ resetSelection();
+ }
+
+public slots:
+ void addUsers(const std::vector<SearchResult> &users);
+ void addRooms(const std::vector<RoomSearchResult> &rooms);
+
+ //! Move to the next available suggestion item.
+ void selectNextSuggestion();
+ //! Move to the previous available suggestion item.
+ void selectPreviousSuggestion();
+ //! Remove hovering from all items.
+ void resetHovering();
+ //! Set hovering to the item in the given layout position.
+ void setHovering(int pos);
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+
+signals:
+ void itemSelected(const QString &user);
+
+private:
+ void hoverSelection();
+ void resetSelection() { selectedItem_ = -1; }
+ void selectFirstItem() { selectedItem_ = 0; }
+ void selectLastItem() { selectedItem_ = layout_->count() - 1; }
+ void removeLayoutItemsAfter(size_t startingPos)
+ {
+ size_t posToRemove = layout_->count() - 1;
+
+ QLayoutItem *item;
+ while (startingPos <= posToRemove &&
+ (item = layout_->takeAt(posToRemove)) != nullptr) {
+ delete item->widget();
+ delete item;
+
+ posToRemove = layout_->count() - 1;
+ }
+ }
+
+ QVBoxLayout *layout_;
+
+ //! Counter for tab completion (cycling).
+ int selectedItem_ = -1;
+};
diff --git a/src/popups/UserMentions.cpp b/src/popups/UserMentions.cpp
new file mode 100644
index 00000000..2e70dbd3
--- /dev/null
+++ b/src/popups/UserMentions.cpp
@@ -0,0 +1,171 @@
+#include <QPaintEvent>
+#include <QPainter>
+#include <QScrollArea>
+#include <QStyleOption>
+#include <QTabWidget>
+#include <QTimer>
+#include <QVBoxLayout>
+
+#include "Cache.h"
+#include "ChatPage.h"
+#include "Logging.h"
+#include "UserMentions.h"
+//#include "timeline/TimelineItem.h"
+
+using namespace popups;
+
+UserMentions::UserMentions(QWidget *parent)
+ : QWidget{parent}
+{
+ setAttribute(Qt::WA_ShowWithoutActivating, true);
+ setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
+
+ 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("localscrollarea");
+
+ 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("allscrollarea");
+
+ 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 QMap<QString, mtx::responses::Notifications> ¬ifs)
+{
+ nhlog::ui()->debug("Initializing " + std::to_string(notifs.size()) + " notifications.");
+
+ for (const auto &item : notifs) {
+ for (const auto ¬if : item.notifications) {
+ const auto event_id = QString::fromStdString(utils::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);
+
+ pushItem(event_id,
+ user_id,
+ body,
+ room_id,
+ ChatPage::instance()->currentRoom());
+
+ } catch (const lmdb::error &e) {
+ nhlog::db()->warn("error while sending desktop notification: {}",
+ e.what());
+ }
+ }
+ }
+}
+
+void
+UserMentions::showPopup()
+{
+ for (auto widget : all_scroll_layout_->findChildren<QWidget *>()) {
+ delete widget;
+ }
+ for (auto widget : local_scroll_layout_->findChildren<QWidget *>()) {
+ delete widget;
+ }
+
+ auto notifs = cache::getTimelineMentions();
+
+ initializeMentions(notifs);
+ show();
+}
+
+void
+UserMentions::pushItem(const QString &event_id,
+ const QString &user_id,
+ const QString &body,
+ const QString &room_id,
+ const QString ¤t_room_id)
+{
+ (void)event_id;
+ (void)user_id;
+ (void)body;
+ (void)room_id;
+ (void)current_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();
+ // });
+ // }
+}
+
+void
+UserMentions::paintEvent(QPaintEvent *)
+{
+ QStyleOption opt;
+ opt.init(this);
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+}
diff --git a/src/popups/UserMentions.h b/src/popups/UserMentions.h
new file mode 100644
index 00000000..b7c4e51d
--- /dev/null
+++ b/src/popups/UserMentions.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <mtx/responses.hpp>
+
+#include <QMap>
+#include <QString>
+#include <QWidget>
+
+class QPaintEvent;
+class QTabWidget;
+class QScrollArea;
+class QVBoxLayout;
+
+namespace popups {
+
+class UserMentions : public QWidget
+{
+ Q_OBJECT
+public:
+ UserMentions(QWidget *parent = nullptr);
+
+ void initializeMentions(const QMap<QString, mtx::responses::Notifications> ¬ifs);
+ void showPopup();
+
+protected:
+ void paintEvent(QPaintEvent *) override;
+
+private:
+ void pushItem(const QString &event_id,
+ const QString &user_id,
+ const QString &body,
+ const QString &room_id,
+ const QString ¤t_room_id);
+ 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_;
+};
+}
|