mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-25 20:48:52 +03:00
Basic thread filtering
The reply pagination logic is a bit weird rn though.
This commit is contained in:
parent
a87f1be688
commit
857d9cf2b6
5 changed files with 135 additions and 4 deletions
|
@ -364,6 +364,8 @@ set(SRC_FILES
|
||||||
src/timeline/Reaction.h
|
src/timeline/Reaction.h
|
||||||
src/timeline/RoomlistModel.cpp
|
src/timeline/RoomlistModel.cpp
|
||||||
src/timeline/RoomlistModel.h
|
src/timeline/RoomlistModel.h
|
||||||
|
src/timeline/TimelineFilter.cpp
|
||||||
|
src/timeline/TimelineFilter.h
|
||||||
src/timeline/TimelineModel.cpp
|
src/timeline/TimelineModel.cpp
|
||||||
src/timeline/TimelineModel.h
|
src/timeline/TimelineModel.h
|
||||||
src/timeline/TimelineViewManager.cpp
|
src/timeline/TimelineViewManager.cpp
|
||||||
|
|
|
@ -38,7 +38,14 @@ Item {
|
||||||
|
|
||||||
displayMarginBeginning: height / 2
|
displayMarginBeginning: height / 2
|
||||||
displayMarginEnd: height / 2
|
displayMarginEnd: height / 2
|
||||||
model: room
|
|
||||||
|
TimelineFilter {
|
||||||
|
id: filteredTimeline
|
||||||
|
source: room
|
||||||
|
filterByThread: room ? room.thread : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
model: filteredTimeline.filterByThread ? filteredTimeline : room
|
||||||
// reuseItems still has a few bugs, see https://bugreports.qt.io/browse/QTBUG-95105 https://bugreports.qt.io/browse/QTBUG-95107
|
// reuseItems still has a few bugs, see https://bugreports.qt.io/browse/QTBUG-95105 https://bugreports.qt.io/browse/QTBUG-95107
|
||||||
//onModelChanged: if (room) room.sendReset()
|
//onModelChanged: if (room) room.sendReset()
|
||||||
//reuseItems: true
|
//reuseItems: true
|
||||||
|
@ -215,16 +222,18 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These shortcuts use the room timeline because switching to threads and out is annoying otherwise.
|
||||||
|
// Better solution welcome.
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Alt+Up"
|
sequence: "Alt+Up"
|
||||||
onActivated: room.reply = chat.model.indexToId(room.reply ? chat.model.idToIndex(room.reply) + 1 : 0)
|
onActivated: room.reply = room.indexToId(room.reply ? room.idToIndex(room.reply) + 1 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Alt+Down"
|
sequence: "Alt+Down"
|
||||||
onActivated: {
|
onActivated: {
|
||||||
var idx = room.reply ? chat.model.idToIndex(room.reply) - 1 : -1;
|
var idx = room.reply ? room.idToIndex(room.reply) - 1 : -1;
|
||||||
room.reply = idx >= 0 ? chat.model.indexToId(idx) : null;
|
room.reply = idx >= 0 ? room.indexToId(idx) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "encryption/DeviceVerificationFlow.h"
|
#include "encryption/DeviceVerificationFlow.h"
|
||||||
#include "encryption/SelfVerificationStatus.h"
|
#include "encryption/SelfVerificationStatus.h"
|
||||||
#include "timeline/DelegateChooser.h"
|
#include "timeline/DelegateChooser.h"
|
||||||
|
#include "timeline/TimelineFilter.h"
|
||||||
#include "timeline/TimelineViewManager.h"
|
#include "timeline/TimelineViewManager.h"
|
||||||
#include "ui/HiddenEvents.h"
|
#include "ui/HiddenEvents.h"
|
||||||
#include "ui/MxcAnimatedImage.h"
|
#include "ui/MxcAnimatedImage.h"
|
||||||
|
@ -186,6 +187,7 @@ MainWindow::registerQmlTypes()
|
||||||
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
||||||
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
|
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
|
||||||
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
|
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
|
||||||
|
qmlRegisterType<TimelineFilter>("im.nheko", 1, 0, "TimelineFilter");
|
||||||
qmlRegisterUncreatableType<RoomSummary>(
|
qmlRegisterUncreatableType<RoomSummary>(
|
||||||
"im.nheko",
|
"im.nheko",
|
||||||
1,
|
1,
|
||||||
|
|
75
src/timeline/TimelineFilter.cpp
Normal file
75
src/timeline/TimelineFilter.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#include "TimelineFilter.h"
|
||||||
|
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
TimelineFilter::TimelineFilter(QObject *parent)
|
||||||
|
: QSortFilterProxyModel(parent)
|
||||||
|
{
|
||||||
|
setDynamicSortFilter(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineFilter::setThreadId(const QString &t)
|
||||||
|
{
|
||||||
|
nhlog::ui()->debug("Filtering by thread '{}'", t.toStdString());
|
||||||
|
if (this->threadId != t) {
|
||||||
|
this->threadId = t;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
emit threadIdChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineFilter::setSource(TimelineModel *s)
|
||||||
|
{
|
||||||
|
if (auto orig = this->source(); orig != s) {
|
||||||
|
if (orig)
|
||||||
|
disconnect(orig,
|
||||||
|
&TimelineModel::currentIndexChanged,
|
||||||
|
this,
|
||||||
|
&TimelineFilter::currentIndexChanged);
|
||||||
|
this->setSourceModel(s);
|
||||||
|
connect(s, &TimelineModel::currentIndexChanged, this, &TimelineFilter::currentIndexChanged);
|
||||||
|
emit sourceChanged();
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineModel *
|
||||||
|
TimelineFilter::source() const
|
||||||
|
{
|
||||||
|
return qobject_cast<TimelineModel *>(sourceModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineFilter::setCurrentIndex(int idx)
|
||||||
|
{
|
||||||
|
// TODO: maybe send read receipt in thread timeline? Or not at all?
|
||||||
|
if (auto s = source()) {
|
||||||
|
s->setCurrentIndex(this->mapToSource(index(idx, 0)).row());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
TimelineFilter::currentIndex() const
|
||||||
|
{
|
||||||
|
if (auto s = source())
|
||||||
|
return this->mapFromSource(s->index(s->currentIndex())).row();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TimelineFilter::filterAcceptsRow(int source_row, const QModelIndex &) const
|
||||||
|
{
|
||||||
|
if (threadId.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (auto s = sourceModel()) {
|
||||||
|
auto idx = s->index(source_row, 0);
|
||||||
|
return s->data(idx, TimelineModel::EventId) == threadId ||
|
||||||
|
s->data(idx, TimelineModel::ThreadId) == threadId;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
43
src/timeline/TimelineFilter.h
Normal file
43
src/timeline/TimelineFilter.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <mtx/events/power_levels.hpp>
|
||||||
|
|
||||||
|
#include "TimelineModel.h"
|
||||||
|
|
||||||
|
class TimelineFilter : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString filterByThread READ filterByThread WRITE setThreadId NOTIFY threadIdChanged)
|
||||||
|
Q_PROPERTY(TimelineModel *source READ source WRITE setSource NOTIFY sourceChanged)
|
||||||
|
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TimelineFilter(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QString filterByThread() const { return threadId; }
|
||||||
|
TimelineModel *source() const;
|
||||||
|
int currentIndex() const;
|
||||||
|
|
||||||
|
void setThreadId(const QString &t);
|
||||||
|
void setSource(TimelineModel *t);
|
||||||
|
void setCurrentIndex(int idx);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void threadIdChanged();
|
||||||
|
void sourceChanged();
|
||||||
|
void currentIndexChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString threadId;
|
||||||
|
};
|
Loading…
Reference in a new issue