mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
QML the read receipts list
There are probably a few things wrong with this, but I'm going to call it good enough for an initial commit
This commit is contained in:
parent
d955444dc1
commit
4dd994ae00
15 changed files with 360 additions and 271 deletions
|
@ -286,7 +286,6 @@ set(SRC_FILES
|
|||
src/dialogs/Logout.cpp
|
||||
src/dialogs/PreviewUploadOverlay.cpp
|
||||
src/dialogs/ReCaptcha.cpp
|
||||
src/dialogs/ReadReceipts.cpp
|
||||
|
||||
# Emoji
|
||||
src/emoji/EmojiModel.cpp
|
||||
|
@ -352,6 +351,7 @@ set(SRC_FILES
|
|||
src/MemberList.cpp
|
||||
src/MxcImageProvider.cpp
|
||||
src/Olm.cpp
|
||||
src/ReadReceiptsModel.cpp
|
||||
src/RegisterPage.cpp
|
||||
src/SSOHandler.cpp
|
||||
src/CombinedImagePackModel.cpp
|
||||
|
@ -499,7 +499,6 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||
src/dialogs/PreviewUploadOverlay.h
|
||||
src/dialogs/RawMessage.h
|
||||
src/dialogs/ReCaptcha.h
|
||||
src/dialogs/ReadReceipts.h
|
||||
|
||||
# Emoji
|
||||
src/emoji/EmojiModel.h
|
||||
|
@ -558,6 +557,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||
src/MainWindow.h
|
||||
src/MemberList.h
|
||||
src/MxcImageProvider.h
|
||||
src/ReadReceiptsModel.h
|
||||
src/RegisterPage.h
|
||||
src/SSOHandler.h
|
||||
src/CombinedImagePackModel.h
|
||||
|
|
118
resources/qml/ReadReceipts.qml
Normal file
118
resources/qml/ReadReceipts.qml
Normal file
|
@ -0,0 +1,118 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import im.nheko 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: readReceiptsRoot
|
||||
|
||||
property ReadReceiptsModel readReceipts
|
||||
|
||||
x: MainWindow.x + (MainWindow.width / 2) - (width / 2)
|
||||
y: MainWindow.y + (MainWindow.height / 2) - (height / 2)
|
||||
height: 380
|
||||
width: 340
|
||||
minimumHeight: 380
|
||||
minimumWidth: headerTitle.width + 2 * Nheko.paddingMedium
|
||||
palette: Nheko.colors
|
||||
color: Nheko.colors.window
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Nheko.paddingMedium
|
||||
spacing: Nheko.paddingMedium
|
||||
|
||||
Label {
|
||||
id: headerTitle
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
text: qsTr("Read receipts")
|
||||
font.pointSize: fontMetrics.font.pointSize * 1.5
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
palette: Nheko.colors
|
||||
padding: Nheko.paddingMedium
|
||||
ScrollBar.horizontal.visible: false
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: 200
|
||||
Layout.fillWidth: true
|
||||
|
||||
ListView {
|
||||
id: readReceiptsList
|
||||
|
||||
clip: true
|
||||
spacing: Nheko.paddingMedium
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: readReceipts
|
||||
|
||||
delegate: RowLayout {
|
||||
spacing: Nheko.paddingMedium
|
||||
|
||||
Avatar {
|
||||
width: Nheko.avatarSize
|
||||
height: Nheko.avatarSize
|
||||
userid: model.mxid
|
||||
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||
displayName: model.displayName
|
||||
onClicked: Rooms.currentRoom.openUserProfile(model.mxid)
|
||||
ToolTip.visible: avatarHover.hovered
|
||||
ToolTip.text: model.mxid
|
||||
|
||||
HoverHandler {
|
||||
id: avatarHover
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Nheko.paddingSmall
|
||||
|
||||
Label {
|
||||
text: model.displayName
|
||||
color: TimelineManager.userColor(model ? model.mxid : "", Nheko.colors.window)
|
||||
font.pointSize: fontMetrics.font.pointSize
|
||||
ToolTip.visible: displayNameHover.hovered
|
||||
ToolTip.text: model.mxid
|
||||
|
||||
TapHandler {
|
||||
onSingleTapped: chat.model.openUserProfile(userId)
|
||||
}
|
||||
|
||||
CursorShape {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: displayNameHover
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
text: model.timestamp
|
||||
color: Nheko.colors.buttonText
|
||||
font.pointSize: fontMetrics.font.pointSize * 0.9
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -96,6 +96,14 @@ Page {
|
|||
|
||||
}
|
||||
|
||||
Component {
|
||||
id: readReceiptsDialog
|
||||
|
||||
ReadReceipts {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Ctrl+K"
|
||||
onActivated: {
|
||||
|
@ -164,6 +172,17 @@ Page {
|
|||
target: TimelineManager
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onOpenReadReceiptsDialog() {
|
||||
var dialog = readReceiptsDialog.createObject(timelineRoot, {
|
||||
"readReceipts": rr
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
target: Rooms.currentRoom
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onNewInviteState() {
|
||||
if (CallManager.haveCallInvite && Settings.mobileMode) {
|
||||
|
|
|
@ -34,7 +34,7 @@ ImageButton {
|
|||
}
|
||||
onClicked: {
|
||||
if (status == MtxEvent.Read)
|
||||
room.readReceiptsAction(eventId);
|
||||
room.showReadReceipts(eventId);
|
||||
|
||||
}
|
||||
image: {
|
||||
|
|
|
@ -112,7 +112,6 @@
|
|||
</qresource>
|
||||
<qresource prefix="/">
|
||||
<file>qtquickcontrols2.conf</file>
|
||||
|
||||
<file>qml/Root.qml</file>
|
||||
<file>qml/ChatPage.qml</file>
|
||||
<file>qml/CommunitiesList.qml</file>
|
||||
|
@ -177,6 +176,7 @@
|
|||
<file>qml/components/FlatButton.qml</file>
|
||||
<file>qml/RoomMembers.qml</file>
|
||||
<file>qml/InviteDialog.qml</file>
|
||||
<file>qml/ReadReceipts.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/media">
|
||||
<file>media/ring.ogg</file>
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include "notifications/Manager.h"
|
||||
|
||||
#include "dialogs/ReadReceipts.h"
|
||||
#include "timeline/TimelineViewManager.h"
|
||||
|
||||
#include "blurhash.hpp"
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "dialogs/JoinRoom.h"
|
||||
#include "dialogs/LeaveRoom.h"
|
||||
#include "dialogs/Logout.h"
|
||||
#include "dialogs/ReadReceipts.h"
|
||||
|
||||
MainWindow *MainWindow::instance_ = nullptr;
|
||||
|
||||
|
@ -398,27 +397,6 @@ MainWindow::openLogoutDialog()
|
|||
showDialog(dialog);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::openReadReceiptsDialog(const QString &event_id)
|
||||
{
|
||||
auto dialog = new dialogs::ReadReceipts(this);
|
||||
|
||||
const auto room_id = chat_page_->currentRoom();
|
||||
|
||||
try {
|
||||
dialog->addUsers(cache::readReceipts(event_id, room_id));
|
||||
} catch (const lmdb::error &) {
|
||||
nhlog::db()->warn("failed to retrieve read receipts for {} {}",
|
||||
event_id.toStdString(),
|
||||
chat_page_->currentRoom().toStdString());
|
||||
dialog->deleteLater();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
showDialog(dialog);
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::hasActiveDialogs() const
|
||||
{
|
||||
|
|
|
@ -65,7 +65,6 @@ public:
|
|||
std::function<void(const mtx::requests::CreateRoom &request)> callback);
|
||||
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
|
||||
void openLogoutDialog();
|
||||
void openReadReceiptsDialog(const QString &event_id);
|
||||
|
||||
void hideOverlay();
|
||||
void showSolidOverlayModal(QWidget *content,
|
||||
|
|
120
src/ReadReceiptsModel.cpp
Normal file
120
src/ReadReceiptsModel.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "ReadReceiptsModel.h"
|
||||
|
||||
#include <QLocale>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Logging.h"
|
||||
#include "Utils.h"
|
||||
|
||||
ReadReceiptsModel::ReadReceiptsModel(QString event_id, QString room_id, QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
, event_id_{event_id}
|
||||
, room_id_{room_id}
|
||||
{
|
||||
try {
|
||||
addUsers(cache::readReceipts(event_id, room_id));
|
||||
} catch (const lmdb::error &) {
|
||||
nhlog::db()->warn("failed to retrieve read receipts for {} {}",
|
||||
event_id.toStdString(),
|
||||
room_id_.toStdString());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ReadReceiptsModel::~ReadReceiptsModel()
|
||||
{
|
||||
for (const auto &item : readReceipts_)
|
||||
item->deleteLater();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray>
|
||||
ReadReceiptsModel::roleNames() const
|
||||
{
|
||||
return {{Mxid, "mxid"},
|
||||
{DisplayName, "displayName"},
|
||||
{AvatarUrl, "avatarUrl"},
|
||||
{Timestamp, "timestamp"}};
|
||||
}
|
||||
|
||||
QVariant
|
||||
ReadReceiptsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= (int)readReceipts_.size() || index.row() < 0)
|
||||
return {};
|
||||
|
||||
switch (role) {
|
||||
case Mxid:
|
||||
return readReceipts_[index.row()]->mxid();
|
||||
case DisplayName:
|
||||
return readReceipts_[index.row()]->displayName();
|
||||
case AvatarUrl:
|
||||
return readReceipts_[index.row()]->avatarUrl();
|
||||
case Timestamp:
|
||||
// the uint64_t to QVariant conversion was ambiguous, so...
|
||||
return readReceipts_[index.row()]->timestamp();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReadReceiptsModel::addUsers(
|
||||
const std::multimap<uint64_t, std::string, std::greater<uint64_t>> &users)
|
||||
{
|
||||
std::multimap<uint64_t, std::string, std::greater<uint64_t>> unshown;
|
||||
for (const auto &user : users) {
|
||||
if (users_.find(user.first) == users_.end())
|
||||
unshown.emplace(user);
|
||||
}
|
||||
|
||||
beginInsertRows(
|
||||
QModelIndex{}, readReceipts_.length(), readReceipts_.length() + unshown.size() - 1);
|
||||
|
||||
for (const auto &user : unshown)
|
||||
readReceipts_.push_back(
|
||||
new ReadReceipt{QString::fromStdString(user.second), room_id_, user.first, this});
|
||||
|
||||
users_.merge(unshown);
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
ReadReceipt::ReadReceipt(QString mxid, QString room_id, uint64_t timestamp, QObject *parent)
|
||||
: QObject{parent}
|
||||
, mxid_{mxid}
|
||||
, room_id_{room_id}
|
||||
, displayName_{cache::displayName(room_id_, mxid_)}
|
||||
, avatarUrl_{cache::avatarUrl(room_id_, mxid_)}
|
||||
, timestamp_{timestamp}
|
||||
{}
|
||||
|
||||
QString
|
||||
ReadReceipt::timestamp() const
|
||||
{
|
||||
return dateFormat(QDateTime::fromMSecsSinceEpoch(timestamp_));
|
||||
}
|
||||
|
||||
QString
|
||||
ReadReceipt::dateFormat(const QDateTime &then) const
|
||||
{
|
||||
auto now = QDateTime::currentDateTime();
|
||||
auto days = then.daysTo(now);
|
||||
|
||||
if (days == 0)
|
||||
return tr("Today %1")
|
||||
.arg(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||
else if (days < 2)
|
||||
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(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||
|
||||
return QLocale::system().toString(then.time(), QLocale::ShortFormat);
|
||||
}
|
86
src/ReadReceiptsModel.h
Normal file
86
src/ReadReceiptsModel.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef READRECEIPTSMODEL_H
|
||||
#define READRECEIPTSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class ReadReceipt : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString mxid READ mxid CONSTANT)
|
||||
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged)
|
||||
Q_PROPERTY(QString timestamp READ timestamp CONSTANT)
|
||||
|
||||
public:
|
||||
explicit ReadReceipt(QString mxid,
|
||||
QString room_id,
|
||||
uint64_t timestamp,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
QString mxid() const { return mxid_; }
|
||||
QString displayName() const { return displayName_; }
|
||||
QString avatarUrl() const { return avatarUrl_; }
|
||||
QString timestamp() const;
|
||||
|
||||
signals:
|
||||
void displayNameChanged();
|
||||
void avatarUrlChanged();
|
||||
|
||||
private:
|
||||
QString dateFormat(const QDateTime &then) const;
|
||||
|
||||
QString mxid_;
|
||||
QString room_id_;
|
||||
QString displayName_;
|
||||
QString avatarUrl_;
|
||||
uint64_t timestamp_;
|
||||
};
|
||||
|
||||
class ReadReceiptsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString eventId READ eventId CONSTANT)
|
||||
Q_PROPERTY(QString roomId READ roomId CONSTANT)
|
||||
|
||||
public:
|
||||
enum Roles
|
||||
{
|
||||
Mxid,
|
||||
DisplayName,
|
||||
AvatarUrl,
|
||||
Timestamp,
|
||||
};
|
||||
|
||||
explicit ReadReceiptsModel(QString event_id, QString room_id, QObject *parent = nullptr);
|
||||
~ReadReceiptsModel() override;
|
||||
|
||||
QString eventId() const { return event_id_; }
|
||||
QString roomId() const { return room_id_; }
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex &parent) const override
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return readReceipts_.size();
|
||||
}
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
public slots:
|
||||
void addUsers(const std::multimap<uint64_t, std::string, std::greater<uint64_t>> &users);
|
||||
|
||||
private:
|
||||
QString event_id_;
|
||||
QString room_id_;
|
||||
QVector<ReadReceipt *> readReceipts_;
|
||||
std::multimap<uint64_t, std::string, std::greater<uint64_t>> users_;
|
||||
};
|
||||
|
||||
#endif // READRECEIPTSMODEL_H
|
|
@ -1,179 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <QDebug>
|
||||
#include <QIcon>
|
||||
#include <QLabel>
|
||||
#include <QListWidgetItem>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <QShortcut>
|
||||
#include <QStyleOption>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "dialogs/ReadReceipts.h"
|
||||
|
||||
#include "AvatarProvider.h"
|
||||
#include "Cache.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Config.h"
|
||||
#include "Utils.h"
|
||||
#include "ui/Avatar.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
ReceiptItem::ReceiptItem(QWidget *parent,
|
||||
const QString &user_id,
|
||||
uint64_t timestamp,
|
||||
const QString &room_id)
|
||||
: QWidget(parent)
|
||||
{
|
||||
topLayout_ = new QHBoxLayout(this);
|
||||
topLayout_->setMargin(0);
|
||||
|
||||
textLayout_ = new QVBoxLayout;
|
||||
textLayout_->setMargin(0);
|
||||
textLayout_->setSpacing(conf::modals::TEXT_SPACING);
|
||||
|
||||
QFont nameFont;
|
||||
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.1);
|
||||
|
||||
auto displayName = cache::displayName(room_id, user_id);
|
||||
|
||||
avatar_ = new Avatar(this, 44);
|
||||
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);
|
||||
userName_->setFont(nameFont);
|
||||
|
||||
timestamp_ = new QLabel(dateFormat(QDateTime::fromMSecsSinceEpoch(timestamp)), this);
|
||||
|
||||
textLayout_->addWidget(userName_);
|
||||
textLayout_->addWidget(timestamp_);
|
||||
|
||||
topLayout_->addWidget(avatar_);
|
||||
topLayout_->addLayout(textLayout_, 1);
|
||||
|
||||
avatar_->setImage(ChatPage::instance()->currentRoom(), user_id);
|
||||
}
|
||||
|
||||
void
|
||||
ReceiptItem::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
|
||||
QString
|
||||
ReceiptItem::dateFormat(const QDateTime &then) const
|
||||
{
|
||||
auto now = QDateTime::currentDateTime();
|
||||
auto days = then.daysTo(now);
|
||||
|
||||
if (days == 0)
|
||||
return tr("Today %1")
|
||||
.arg(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||
else if (days < 2)
|
||||
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(QLocale::system().toString(then.time(), QLocale::ShortFormat));
|
||||
|
||||
return QLocale::system().toString(then.time(), QLocale::ShortFormat);
|
||||
}
|
||||
|
||||
ReadReceipts::ReadReceipts(QWidget *parent)
|
||||
: QFrame(parent)
|
||||
{
|
||||
setAutoFillBackground(true);
|
||||
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(conf::modals::WIDGET_SPACING);
|
||||
layout->setMargin(conf::modals::WIDGET_MARGIN);
|
||||
|
||||
userList_ = new QListWidget;
|
||||
userList_->setFrameStyle(QFrame::NoFrame);
|
||||
userList_->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
userList_->setSpacing(conf::modals::TEXT_SPACING);
|
||||
|
||||
QFont largeFont;
|
||||
largeFont.setPointSizeF(largeFont.pointSizeF() * 1.5);
|
||||
|
||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
setMinimumHeight(userList_->sizeHint().height() * 2);
|
||||
setMinimumWidth(std::max(userList_->sizeHint().width() + 4 * conf::modals::WIDGET_MARGIN,
|
||||
QFontMetrics(largeFont).averageCharWidth() * 30 -
|
||||
2 * conf::modals::WIDGET_MARGIN));
|
||||
|
||||
QFont font;
|
||||
font.setPointSizeF(font.pointSizeF() * conf::modals::LABEL_MEDIUM_SIZE_RATIO);
|
||||
|
||||
topLabel_ = new QLabel(tr("Read receipts"), this);
|
||||
topLabel_->setAlignment(Qt::AlignCenter);
|
||||
topLabel_->setFont(font);
|
||||
|
||||
auto okBtn = new QPushButton(tr("Close"), this);
|
||||
|
||||
auto buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->setSpacing(15);
|
||||
buttonLayout->addStretch(1);
|
||||
buttonLayout->addWidget(okBtn);
|
||||
|
||||
layout->addWidget(topLabel_);
|
||||
layout->addWidget(userList_);
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
auto closeShortcut = new QShortcut(QKeySequence(QKeySequence::Cancel), this);
|
||||
connect(closeShortcut, &QShortcut::activated, this, &ReadReceipts::close);
|
||||
connect(okBtn, &QPushButton::clicked, this, &ReadReceipts::close);
|
||||
}
|
||||
|
||||
void
|
||||
ReadReceipts::addUsers(const std::multimap<uint64_t, std::string, std::greater<uint64_t>> &receipts)
|
||||
{
|
||||
// We want to remove any previous items that have been set.
|
||||
userList_->clear();
|
||||
|
||||
for (const auto &receipt : receipts) {
|
||||
auto user = new ReceiptItem(this,
|
||||
QString::fromStdString(receipt.second),
|
||||
receipt.first,
|
||||
ChatPage::instance()->currentRoom());
|
||||
auto item = new QListWidgetItem(userList_);
|
||||
|
||||
item->setSizeHint(user->minimumSizeHint());
|
||||
item->setFlags(Qt::NoItemFlags);
|
||||
item->setTextAlignment(Qt::AlignCenter);
|
||||
|
||||
userList_->setItemWidget(item, user);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReadReceipts::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
|
||||
void
|
||||
ReadReceipts::hideEvent(QHideEvent *event)
|
||||
{
|
||||
userList_->clear();
|
||||
QFrame::hideEvent(event);
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QFrame>
|
||||
|
||||
class Avatar;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class ReceiptItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ReceiptItem(QWidget *parent,
|
||||
const QString &user_id,
|
||||
uint64_t timestamp,
|
||||
const QString &room_id);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
private:
|
||||
QString dateFormat(const QDateTime &then) const;
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
QVBoxLayout *textLayout_;
|
||||
|
||||
Avatar *avatar_;
|
||||
|
||||
QLabel *userName_;
|
||||
QLabel *timestamp_;
|
||||
};
|
||||
|
||||
class ReadReceipts : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ReadReceipts(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addUsers(const std::multimap<uint64_t, std::string, std::greater<uint64_t>> &users);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
|
||||
private:
|
||||
QLabel *topLabel_;
|
||||
|
||||
QListWidget *userList_;
|
||||
};
|
||||
} // dialogs
|
|
@ -28,6 +28,7 @@
|
|||
#include "MemberList.h"
|
||||
#include "MxcImageProvider.h"
|
||||
#include "Olm.h"
|
||||
#include "ReadReceiptsModel.h"
|
||||
#include "TimelineViewManager.h"
|
||||
#include "Utils.h"
|
||||
#include "dialogs/RawMessage.h"
|
||||
|
@ -1089,9 +1090,9 @@ TimelineModel::relatedInfo(QString id)
|
|||
}
|
||||
|
||||
void
|
||||
TimelineModel::readReceiptsAction(QString id) const
|
||||
TimelineModel::showReadReceipts(QString id)
|
||||
{
|
||||
MainWindow::instance()->openReadReceiptsDialog(id);
|
||||
emit openReadReceiptsDialog(new ReadReceiptsModel{id, roomId(), this});
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "InviteesModel.h"
|
||||
#include "MemberList.h"
|
||||
#include "Permissions.h"
|
||||
#include "ReadReceiptsModel.h"
|
||||
#include "ui/RoomSettings.h"
|
||||
#include "ui/UserProfile.h"
|
||||
|
||||
|
@ -241,7 +242,7 @@ public:
|
|||
Q_INVOKABLE void openUserProfile(QString userid);
|
||||
Q_INVOKABLE void editAction(QString id);
|
||||
Q_INVOKABLE void replyAction(QString id);
|
||||
Q_INVOKABLE void readReceiptsAction(QString id) const;
|
||||
Q_INVOKABLE void showReadReceipts(QString id);
|
||||
Q_INVOKABLE void redactEvent(QString id);
|
||||
Q_INVOKABLE int idToIndex(QString id) const;
|
||||
Q_INVOKABLE QString indexToId(int index) const;
|
||||
|
@ -348,6 +349,7 @@ signals:
|
|||
void typingUsersChanged(std::vector<QString> users);
|
||||
void replyChanged(QString reply);
|
||||
void editChanged(QString reply);
|
||||
void openReadReceiptsDialog(ReadReceiptsModel *rr);
|
||||
void paginationInProgressChanged(const bool);
|
||||
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
|
||||
void scrollToIndex(int index);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "MainWindow.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "MxcImageProvider.h"
|
||||
#include "ReadReceiptsModel.h"
|
||||
#include "RoomsModel.h"
|
||||
#include "SingleImagePackModel.h"
|
||||
#include "UserSettingsPage.h"
|
||||
|
@ -205,6 +206,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||
0,
|
||||
"InviteesModel",
|
||||
"InviteesModel needs to be instantiated on the C++ side");
|
||||
qmlRegisterUncreatableType<ReadReceiptsModel>(
|
||||
"im.nheko",
|
||||
1,
|
||||
0,
|
||||
"ReadReceiptsModel",
|
||||
"ReadReceiptsModel needs to be instantiated on the C++ side");
|
||||
|
||||
static auto self = this;
|
||||
qmlRegisterSingletonType<MainWindow>(
|
||||
|
|
Loading…
Reference in a new issue