Faster timeline.

Also, fixes markdown formatting.
square-messages
Black Hat 2018-10-07 20:15:59 +08:00
parent a62792fa3b
commit c93efebd23
6 changed files with 8 additions and 118 deletions

View File

@ -1,6 +1,10 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import Spectral 0.1
import "qrc:/js/md.js" as Markdown
TextArea {
property real progress: 0

View File

@ -12,14 +12,14 @@ Menu {
checkable: true
checked: model && model.category === RoomType.Favorite
onTriggered: model.category === RoomType.Favorite ? model.currentRoom.removeTag("m.favourite") : model.currentRoom.addTag("m.favourite", "1")
onTriggered: model.category === RoomType.Favorite ? model.currentRoom.removeTag("m.favourite") : model.currentRoom.addTag("m.favourite", 1.0)
}
MenuItem {
text: "Deprioritize"
checkable: true
checked: model && model.category === RoomType.Deprioritized
onTriggered: model.category === RoomType.Deprioritized ? model.currentRoom.removeTag("m.lowpriority") : model.currentRoom.addTag("m.lowpriority", "1")
onTriggered: model.category === RoomType.Deprioritized ? model.currentRoom.removeTag("m.lowpriority") : model.currentRoom.addTag("m.lowpriority", 1.0)
}
MenuSeparator {}
MenuItem {

View File

@ -87,12 +87,7 @@ void MessageEventModel::setRoom(SpectralRoom* room) {
{AboveEventTypeRole, AboveAuthorRole,
AboveSectionRole, AboveTimeRole});
}
for (auto i = m_currentRoom->maxTimelineIndex() - biggest;
i <= m_currentRoom->maxTimelineIndex() - lowest; ++i)
refreshLastUserEvents(i);
},
Qt::QueuedConnection);
});
connect(m_currentRoom, &Room::pendingEventAboutToAdd, this,
[this] { beginInsertRows({}, 0, 0); });
connect(m_currentRoom, &Room::pendingEventAdded, this,
@ -111,8 +106,7 @@ void MessageEventModel::setRoom(SpectralRoom* room) {
endMoveRows();
movingEvent = false;
}
refreshRow(timelineBaseIndex()); // Refresh the looks
refreshLastUserEvents(0);
refreshRow(timelineBaseIndex()); // Refresh the looks
if (m_currentRoom->timelineSize() > 1) // Refresh above
refreshEventRoles(timelineBaseIndex() + 1, {ReadMarkerRole});
if (timelineBaseIndex() > 0) // Refresh below, see #312
@ -132,11 +126,6 @@ void MessageEventModel::setRoom(SpectralRoom* room) {
{ReadMarkerRole});
refreshEventRoles(lastReadEventId, {ReadMarkerRole});
});
connect(m_currentRoom, &Room::replacedEvent, this,
[this](const RoomEvent* newEvent) {
refreshLastUserEvents(refreshEvent(newEvent->id()) -
timelineBaseIndex());
});
connect(m_currentRoom, &Room::fileTransferProgress, this,
&MessageEventModel::refreshEvent);
connect(m_currentRoom, &Room::fileTransferCompleted, this,
@ -220,82 +209,6 @@ QString MessageEventModel::renderDate(QDateTime timestamp) const {
return date.toString(Qt::DefaultLocaleShortDate);
}
bool MessageEventModel::isUserActivityNotable(
const QMatrixClient::Room::rev_iter_t& baseIt) const {
const auto& senderId = (*baseIt)->senderId();
// TODO: Go up and down the timeline (limit to 100 events for
// the sake of performance) and collect all messages of
// this author; find out if there's anything besides joins, leaves
// and redactions; if not, double-check whether the current event is
// a part of a re-join without following redactions.
using namespace QMatrixClient;
bool joinFound = false, redactionsFound = false;
// Find the nearest join of this user above, or a no-nonsense event.
for (auto it = baseIt,
limit = baseIt +
std::min(int(m_currentRoom->timelineEdge() - baseIt), 100);
it != limit; ++it) {
const auto& e = **it;
if (e.senderId() != senderId) continue;
if (e.isRedacted()) {
redactionsFound = true;
continue;
}
if (auto* me = it->viewAs<QMatrixClient::RoomMemberEvent>()) {
if (me->isJoin()) {
joinFound = true;
break;
}
continue;
}
return true; // Consider all other events notable
}
// Find the nearest leave of this user below, or a no-nonsense event
bool leaveFound = false;
for (auto it = baseIt.base() - 1,
limit = baseIt.base() +
std::min(int(m_currentRoom->messageEvents().end() -
baseIt.base()),
100);
it != limit; ++it) {
const auto& e = **it;
if (e.senderId() != senderId) continue;
if (e.isRedacted()) {
redactionsFound = true;
continue;
}
if (auto* me = it->viewAs<RoomMemberEvent>()) {
if (me->isLeave() || me->membership() == MembershipType::Ban) {
leaveFound = true;
break;
}
continue;
}
return true;
}
// If we are here, it means that no notable events have been found in
// the timeline vicinity, and probably redactions are there. Doesn't look
// notable but let's give some benefit of doubt.
if (redactionsFound) return false; // Join + redactions or redactions + leave
return !(joinFound && leaveFound); // Join + (maybe profile changes) + leave
}
void MessageEventModel::refreshLastUserEvents(int baseTimelineRow) {
if (!m_currentRoom || m_currentRoom->timelineSize() <= baseTimelineRow)
return;
const auto& timelineBottom = m_currentRoom->messageEvents().rbegin();
const auto& lastSender = (*(timelineBottom + baseTimelineRow))->senderId();
const auto limit = timelineBottom + std::min(baseTimelineRow + 100,
m_currentRoom->timelineSize());
for (auto it = timelineBottom + std::max(baseTimelineRow - 100, 0);
it != limit; ++it) {
if ((*it)->senderId() == lastSender) {
auto idx = index(it - timelineBottom);
emit dataChanged(idx, idx);
}
}
}
int MessageEventModel::rowCount(const QModelIndex& parent) const {
if (!m_currentRoom || parent.isValid()) return 0;
return m_currentRoom->timelineSize();
@ -500,20 +413,6 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
if (isPending) return pendingIt->deliveryStatus();
if (is<RedactionEvent>(evt)) return EventStatus::Hidden;
auto* memberEvent = timelineIt->viewAs<RoomMemberEvent>();
if (memberEvent) {
if ((memberEvent->isJoin() || memberEvent->isLeave()))
return EventStatus::Hidden;
}
if (memberEvent || evt.isRedacted()) {
if (evt.senderId() == m_currentRoom->localUser()->id()) {
// QElapsedTimer et; et.start();
auto hide = !isUserActivityNotable(timelineIt);
// qDebug() << "Checked user activity for" << evt.id() <<
// "in" << et;
if (hide) return EventStatus::Hidden;
}
}
if (evt.isRedacted()) return EventStatus::Redacted;
if (evt.isStateEvent() &&

View File

@ -59,10 +59,7 @@ class MessageEventModel : public QAbstractListModel {
QDateTime makeMessageTimestamp(
const QMatrixClient::Room::rev_iter_t& baseIt) const;
QString renderDate(QDateTime timestamp) const;
bool isUserActivityNotable(
const QMatrixClient::Room::rev_iter_t& baseIt) const;
void refreshLastUserEvents(int baseRow);
void refreshEventRoles(int row, const QVector<int>& roles = {});
int refreshEventRoles(const QString& eventId, const QVector<int>& roles = {});

View File

@ -178,11 +178,3 @@ void SpectralRoom::saveViewport(int topIndex, int bottomIndex) {
setFirstDisplayedEvent(maxTimelineIndex() - topIndex);
setLastDisplayedEvent(maxTimelineIndex() - bottomIndex);
}
void SpectralRoom::getPreviousContent(int limit) {
setBusy(true);
QMetaObject::invokeMethod(
this,
[=] { Room::getPreviousContent(limit); },
Qt::QueuedConnection);
}

View File

@ -52,8 +52,6 @@ class SpectralRoom : public Room {
Q_INVOKABLE int savedBottomVisibleIndex() const;
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
Q_INVOKABLE void getPreviousContent(int limit = 10);
private:
QString m_cachedInput;
QSet<const QMatrixClient::RoomEvent*> highlights;