Basic thread filtering

The reply pagination logic is a bit weird rn though.
pull/1161/head
Nicolas Werner 2 years ago
parent a87f1be688
commit 857d9cf2b6
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
  1. 2
      CMakeLists.txt
  2. 17
      resources/qml/MessageView.qml
  3. 2
      src/MainWindow.cpp
  4. 75
      src/timeline/TimelineFilter.cpp
  5. 43
      src/timeline/TimelineFilter.h

@ -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,

@ -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;
}
}

@ -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…
Cancel
Save