Highlight navigated to message
This commit is contained in:
parent
620b6e8838
commit
82fa8ab292
@ -25,10 +25,6 @@ Popup {
|
|||||||
height: implicitHeight + completerPopup.height + padding * 2
|
height: implicitHeight + completerPopup.height + padding * 2
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
rightPadding: 10
|
rightPadding: 10
|
||||||
background: Rectangle {
|
|
||||||
color: colors.window
|
|
||||||
}
|
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
completerPopup.open();
|
completerPopup.open();
|
||||||
roomTextInput.forceActiveFocus();
|
roomTextInput.forceActiveFocus();
|
||||||
@ -110,6 +106,10 @@ Popup {
|
|||||||
target: completerPopup
|
target: completerPopup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: colors.window
|
||||||
|
}
|
||||||
|
|
||||||
Overlay.modal: Rectangle {
|
Overlay.modal: Rectangle {
|
||||||
color: Qt.rgba(colors.window.r, colors.window.g, colors.window.b, 0.7)
|
color: Qt.rgba(colors.window.r, colors.window.g, colors.window.b, 0.7)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ TextEdit {
|
|||||||
selectByMouse: !Settings.mobileMode
|
selectByMouse: !Settings.mobileMode
|
||||||
enabled: selectByMouse
|
enabled: selectByMouse
|
||||||
color: colors.text
|
color: colors.text
|
||||||
onLinkActivated: TimelineManager.openLink(link);
|
onLinkActivated: TimelineManager.openLink(link)
|
||||||
ToolTip.visible: hoveredLink
|
ToolTip.visible: hoveredLink
|
||||||
ToolTip.text: hoveredLink
|
ToolTip.text: hoveredLink
|
||||||
|
|
||||||
|
@ -258,6 +258,7 @@ ScrollView {
|
|||||||
onRoomAvatarUrlChanged: {
|
onRoomAvatarUrlChanged: {
|
||||||
messageUserAvatar.url = modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : "";
|
messageUserAvatar.url = modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : "";
|
||||||
}
|
}
|
||||||
|
onScrollToIndex: chat.positionViewAtIndex(index, ListView.Visible)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
@ -302,10 +303,58 @@ ScrollView {
|
|||||||
delegate: Item {
|
delegate: Item {
|
||||||
id: wrapper
|
id: wrapper
|
||||||
|
|
||||||
|
property bool scrolledToThis: model.id === chat.model.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY)
|
||||||
|
|
||||||
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
|
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
|
||||||
width: chat.delegateMaxWidth
|
width: chat.delegateMaxWidth
|
||||||
height: section ? section.height + timelinerow.height : timelinerow.height
|
height: section ? section.height + timelinerow.height : timelinerow.height
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: scrollHighlight
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
visible: true
|
||||||
|
anchors.fill: timelinerow
|
||||||
|
color: colors.highlight
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "revealed"
|
||||||
|
when: wrapper.scrolledToThis
|
||||||
|
}
|
||||||
|
|
||||||
|
transitions: Transition {
|
||||||
|
from: ""
|
||||||
|
to: "revealed"
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAnimation {
|
||||||
|
target: scrollHighlight
|
||||||
|
properties: "opacity"
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAnimation {
|
||||||
|
target: scrollHighlight
|
||||||
|
properties: "opacity"
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptAction {
|
||||||
|
script: chat.model.eventShown()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: section
|
id: section
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import im.nheko 1.0
|
|||||||
Item {
|
Item {
|
||||||
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? parent.width : model.data.width)
|
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? parent.width : model.data.width)
|
||||||
property double tempHeight: tempWidth * model.data.proportionalHeight
|
property double tempHeight: tempWidth * model.data.proportionalHeight
|
||||||
property double divisor: model.isReply ? 4 : 2
|
property double divisor: model.isReply ? 5 : 3
|
||||||
property bool tooHigh: tempHeight > timelineRoot.height / divisor
|
property bool tooHigh: tempHeight > timelineRoot.height / divisor
|
||||||
|
|
||||||
height: Math.round(tooHigh ? timelineRoot.height / divisor : tempHeight)
|
height: Math.round(tooHigh ? timelineRoot.height / divisor : tempHeight)
|
||||||
|
@ -18,7 +18,7 @@ Item {
|
|||||||
height: replyContainer.height
|
height: replyContainer.height
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
onSingleTapped: chat.positionViewAtIndex(chat.model.idToIndex(modelData.id), ListView.Contain)
|
onSingleTapped: chat.model.showEvent(modelData.id)
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1376,7 +1376,7 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QString mxid2;
|
QString mxid2;
|
||||||
if (segments.size() == 4 && segments[2] == "event") {
|
if (segments.size() == 4 && segments[2] == "e") {
|
||||||
if (segments[3].isEmpty())
|
if (segments[3].isEmpty())
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
@ -1410,6 +1410,8 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
|
|||||||
for (auto roomid : joined_rooms) {
|
for (auto roomid : joined_rooms) {
|
||||||
if (roomid == targetRoomId) {
|
if (roomid == targetRoomId) {
|
||||||
room_list_->highlightSelectedRoom(mxid1);
|
room_list_->highlightSelectedRoom(mxid1);
|
||||||
|
if (!mxid2.isEmpty())
|
||||||
|
view_manager_->showEvent(mxid1, mxid2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1427,6 +1429,9 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
|
|||||||
if (aliases->alias == targetRoomAlias) {
|
if (aliases->alias == targetRoomAlias) {
|
||||||
room_list_->highlightSelectedRoom(
|
room_list_->highlightSelectedRoom(
|
||||||
QString::fromStdString(roomid));
|
QString::fromStdString(roomid));
|
||||||
|
if (!mxid2.isEmpty())
|
||||||
|
view_manager_->showEvent(
|
||||||
|
QString::fromStdString(roomid), mxid2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,8 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
|
|||||||
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
|
connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) {
|
||||||
this->updateFlowEventId(event_id);
|
this->updateFlowEventId(event_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray>
|
QHash<int, QByteArray>
|
||||||
@ -1298,6 +1300,42 @@ TimelineModel::cacheMedia(QString eventId)
|
|||||||
cacheMedia(eventId, NULL);
|
cacheMedia(eventId, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::showEvent(QString eventId)
|
||||||
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
if (idToIndex(eventId) != -1) {
|
||||||
|
eventIdToShow = eventId;
|
||||||
|
emit scrollTargetChanged();
|
||||||
|
showEventTimer.start(50ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::eventShown()
|
||||||
|
{
|
||||||
|
eventIdToShow.clear();
|
||||||
|
emit scrollTargetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
TimelineModel::scrollTarget() const
|
||||||
|
{
|
||||||
|
return eventIdToShow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineModel::scrollTimerEvent()
|
||||||
|
{
|
||||||
|
if (eventIdToShow.isEmpty() || showEventTimerCounter > 3) {
|
||||||
|
showEventTimer.stop();
|
||||||
|
showEventTimerCounter = 0;
|
||||||
|
} else {
|
||||||
|
emit scrollToIndex(idToIndex(eventIdToShow));
|
||||||
|
showEventTimerCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TimelineModel::formatTypingUsers(const std::vector<QString> &users, QColor bg)
|
TimelineModel::formatTypingUsers(const std::vector<QString> &users, QColor bg)
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <mtxclient/http/errors.hpp>
|
#include <mtxclient/http/errors.hpp>
|
||||||
|
|
||||||
@ -149,6 +150,7 @@ class TimelineModel : public QAbstractListModel
|
|||||||
int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
|
||||||
Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
|
Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
|
||||||
typingUsersChanged)
|
typingUsersChanged)
|
||||||
|
Q_PROPERTY(QString scrollTarget READ scrollTarget NOTIFY scrollTargetChanged)
|
||||||
Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply)
|
Q_PROPERTY(QString reply READ reply WRITE setReply NOTIFY replyChanged RESET resetReply)
|
||||||
Q_PROPERTY(QString edit READ edit WRITE setEdit NOTIFY editChanged RESET resetEdit)
|
Q_PROPERTY(QString edit READ edit WRITE setEdit NOTIFY editChanged RESET resetEdit)
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
@ -232,6 +234,7 @@ public:
|
|||||||
Q_INVOKABLE void openMedia(QString eventId);
|
Q_INVOKABLE void openMedia(QString eventId);
|
||||||
Q_INVOKABLE void cacheMedia(QString eventId);
|
Q_INVOKABLE void cacheMedia(QString eventId);
|
||||||
Q_INVOKABLE bool saveMedia(QString eventId) const;
|
Q_INVOKABLE bool saveMedia(QString eventId) const;
|
||||||
|
Q_INVOKABLE void showEvent(QString eventId);
|
||||||
void cacheMedia(QString eventId, std::function<void(const QString filename)> callback);
|
void cacheMedia(QString eventId, std::function<void(const QString filename)> callback);
|
||||||
|
|
||||||
std::vector<::Reaction> reactions(const std::string &event_id)
|
std::vector<::Reaction> reactions(const std::string &event_id)
|
||||||
@ -253,6 +256,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void setCurrentIndex(int index);
|
void setCurrentIndex(int index);
|
||||||
int currentIndex() const { return idToIndex(currentId); }
|
int currentIndex() const { return idToIndex(currentId); }
|
||||||
|
void eventShown();
|
||||||
void markEventsAsRead(const std::vector<QString> &event_ids);
|
void markEventsAsRead(const std::vector<QString> &event_ids);
|
||||||
QVariantMap getDump(QString eventId, QString relatedTo) const;
|
QVariantMap getDump(QString eventId, QString relatedTo) const;
|
||||||
void updateTypingUsers(const std::vector<QString> &users)
|
void updateTypingUsers(const std::vector<QString> &users)
|
||||||
@ -298,8 +302,11 @@ public slots:
|
|||||||
QString roomAvatarUrl() const;
|
QString roomAvatarUrl() const;
|
||||||
QString roomId() const { return room_id_; }
|
QString roomId() const { return room_id_; }
|
||||||
|
|
||||||
|
QString scrollTarget() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
void addPendingMessage(mtx::events::collections::TimelineEvents event);
|
||||||
|
void scrollTimerEvent();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentIndexChanged(int index);
|
void currentIndexChanged(int index);
|
||||||
@ -312,6 +319,7 @@ signals:
|
|||||||
void editChanged(QString reply);
|
void editChanged(QString reply);
|
||||||
void paginationInProgressChanged(const bool);
|
void paginationInProgressChanged(const bool);
|
||||||
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
|
void newCallEvent(const mtx::events::collections::TimelineEvents &event);
|
||||||
|
void scrollToIndex(int index);
|
||||||
|
|
||||||
void openProfile(UserProfile *profile);
|
void openProfile(UserProfile *profile);
|
||||||
void openRoomSettingsDialog(RoomSettings *settings);
|
void openRoomSettingsDialog(RoomSettings *settings);
|
||||||
@ -325,6 +333,8 @@ signals:
|
|||||||
void roomAvatarUrlChanged();
|
void roomAvatarUrlChanged();
|
||||||
void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
|
void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
|
||||||
|
|
||||||
|
void scrollTargetChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType);
|
void sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType);
|
||||||
@ -350,6 +360,10 @@ private:
|
|||||||
|
|
||||||
InputBar input_{this};
|
InputBar input_{this};
|
||||||
|
|
||||||
|
QTimer showEventTimer{this};
|
||||||
|
QString eventIdToShow;
|
||||||
|
int showEventTimerCounter = 0;
|
||||||
|
|
||||||
friend struct SendMessageVisitor;
|
friend struct SendMessageVisitor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -404,6 +404,22 @@ TimelineViewManager::highlightRoom(const QString &room_id)
|
|||||||
ChatPage::instance()->highlightRoom(room_id);
|
ChatPage::instance()->highlightRoom(room_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
|
||||||
|
{
|
||||||
|
auto room = models.find(room_id);
|
||||||
|
if (room != models.end()) {
|
||||||
|
if (timeline_ != room.value().data()) {
|
||||||
|
timeline_ = room.value().data();
|
||||||
|
emit activeTimelineChanged(timeline_);
|
||||||
|
container->setFocus();
|
||||||
|
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
timeline_->showEvent(event_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TimelineViewManager::escapeEmoji(QString str) const
|
TimelineViewManager::escapeEmoji(QString str) const
|
||||||
{
|
{
|
||||||
|
@ -106,6 +106,7 @@ public slots:
|
|||||||
|
|
||||||
void setHistoryView(const QString &room_id);
|
void setHistoryView(const QString &room_id);
|
||||||
void highlightRoom(const QString &room_id);
|
void highlightRoom(const QString &room_id);
|
||||||
|
void showEvent(const QString &room_id, const QString &event_id);
|
||||||
void focusTimeline();
|
void focusTimeline();
|
||||||
TimelineModel *getHistoryView(const QString &room_id)
|
TimelineModel *getHistoryView(const QString &room_id)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user