mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 19:08:58 +03:00
Move currentRoom/timeline handling to roomlist
This commit is contained in:
parent
e2765212fb
commit
298822baea
30 changed files with 349 additions and 345 deletions
|
@ -31,6 +31,7 @@ Rectangle {
|
||||||
|
|
||||||
TimelineView {
|
TimelineView {
|
||||||
id: timeline
|
id: timeline
|
||||||
|
room: Rooms.currentRoom
|
||||||
|
|
||||||
SplitView.fillWidth: true
|
SplitView.fillWidth: true
|
||||||
SplitView.minimumWidth: 400
|
SplitView.minimumWidth: 400
|
||||||
|
|
|
@ -70,7 +70,7 @@ Popup {
|
||||||
onCompleterNameChanged: {
|
onCompleterNameChanged: {
|
||||||
if (completerName) {
|
if (completerName) {
|
||||||
if (completerName == "user")
|
if (completerName == "user")
|
||||||
completer = TimelineManager.completerFor(completerName, TimelineManager.timeline.roomId());
|
completer = TimelineManager.completerFor(completerName, room.roomId());
|
||||||
else
|
else
|
||||||
completer = TimelineManager.completerFor(completerName);
|
completer = TimelineManager.completerFor(completerName);
|
||||||
completer.setSearchString("");
|
completer.setSearchString("");
|
||||||
|
@ -83,8 +83,8 @@ Popup {
|
||||||
height: listView.contentHeight + 2 // + 2 for the padding on top and bottom
|
height: listView.contentHeight + 2 // + 2 for the padding on top and bottom
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onTimelineChanged: completer = null
|
onRoomChanged: completer = null
|
||||||
target: TimelineManager
|
target: timelineView
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
|
|
|
@ -50,7 +50,7 @@ Popup {
|
||||||
Reply {
|
Reply {
|
||||||
id: replyPreview
|
id: replyPreview
|
||||||
|
|
||||||
modelData: TimelineManager.timeline ? TimelineManager.timeline.getDump(mid, "") : {
|
modelData: room ? room.getDump(mid, "") : {
|
||||||
}
|
}
|
||||||
userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.window)
|
userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.window)
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ Popup {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onCompletionSelected: {
|
onCompletionSelected: {
|
||||||
TimelineManager.timeline.forwardMessage(messageContextMenu.eventId, id);
|
room.forwardMessage(messageContextMenu.eventId, id);
|
||||||
forwardMessagePopup.close();
|
forwardMessagePopup.close();
|
||||||
}
|
}
|
||||||
onCountChanged: {
|
onCountChanged: {
|
||||||
|
|
|
@ -28,7 +28,7 @@ Rectangle {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: row
|
id: row
|
||||||
|
|
||||||
visible: (TimelineManager.timeline ? TimelineManager.timeline.permissions.canSend(MtxEvent.TextMessage) : false) || messageContextMenu.isSender
|
visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
ImageButton {
|
ImageButton {
|
||||||
|
@ -43,7 +43,7 @@ Rectangle {
|
||||||
ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : qsTr("Place a call")
|
ToolTip.text: CallManager.isOnCall ? qsTr("Hang up") : qsTr("Place a call")
|
||||||
Layout.margins: 8
|
Layout.margins: 8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (TimelineManager.timeline) {
|
if (room) {
|
||||||
if (CallManager.haveCallInvite) {
|
if (CallManager.haveCallInvite) {
|
||||||
return ;
|
return ;
|
||||||
} else if (CallManager.isOnCall) {
|
} else if (CallManager.isOnCall) {
|
||||||
|
@ -63,14 +63,14 @@ Rectangle {
|
||||||
height: 22
|
height: 22
|
||||||
image: ":/icons/icons/ui/paper-clip-outline.png"
|
image: ":/icons/icons/ui/paper-clip-outline.png"
|
||||||
Layout.margins: 8
|
Layout.margins: 8
|
||||||
onClicked: TimelineManager.timeline.input.openFileSelection()
|
onClicked: room.input.openFileSelection()
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: qsTr("Send a file")
|
ToolTip.text: qsTr("Send a file")
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Nheko.colors.window
|
color: Nheko.colors.window
|
||||||
visible: TimelineManager.timeline && TimelineManager.timeline.input.uploading
|
visible: room && room.input.uploading
|
||||||
|
|
||||||
NhekoBusyIndicator {
|
NhekoBusyIndicator {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -123,16 +123,16 @@ Rectangle {
|
||||||
padding: 8
|
padding: 8
|
||||||
focus: true
|
focus: true
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (TimelineManager.timeline)
|
if (room)
|
||||||
TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
room.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
||||||
|
|
||||||
forceActiveFocus();
|
forceActiveFocus();
|
||||||
}
|
}
|
||||||
onCursorPositionChanged: {
|
onCursorPositionChanged: {
|
||||||
if (!TimelineManager.timeline)
|
if (!room)
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
room.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
||||||
if (cursorPosition <= completerTriggeredAt) {
|
if (cursorPosition <= completerTriggeredAt) {
|
||||||
completerTriggeredAt = -1;
|
completerTriggeredAt = -1;
|
||||||
popup.close();
|
popup.close();
|
||||||
|
@ -141,13 +141,13 @@ Rectangle {
|
||||||
popup.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition));
|
popup.completer.setSearchString(messageInput.getText(completerTriggeredAt, cursorPosition));
|
||||||
|
|
||||||
}
|
}
|
||||||
onSelectionStartChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onSelectionStartChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
onSelectionEndChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onSelectionEndChanged: room.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
// Ensure that we get escape key press events first.
|
// Ensure that we get escape key press events first.
|
||||||
Keys.onShortcutOverride: event.accepted = (completerTriggeredAt != -1 && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter))
|
Keys.onShortcutOverride: event.accepted = (completerTriggeredAt != -1 && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter))
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (event.matches(StandardKey.Paste)) {
|
if (event.matches(StandardKey.Paste)) {
|
||||||
TimelineManager.timeline.input.paste(false);
|
room.input.paste(false);
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
} else if (event.key == Qt.Key_Space) {
|
} else if (event.key == Qt.Key_Space) {
|
||||||
// close popup if user enters space after colon
|
// close popup if user enters space after colon
|
||||||
|
@ -160,9 +160,9 @@ Rectangle {
|
||||||
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_U) {
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_U) {
|
||||||
messageInput.clear();
|
messageInput.clear();
|
||||||
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_P) {
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_P) {
|
||||||
messageInput.text = TimelineManager.timeline.input.previousText();
|
messageInput.text = room.input.previousText();
|
||||||
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_N) {
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_N) {
|
||||||
messageInput.text = TimelineManager.timeline.input.nextText();
|
messageInput.text = room.input.nextText();
|
||||||
} else if (event.key == Qt.Key_At) {
|
} else if (event.key == Qt.Key_At) {
|
||||||
messageInput.openCompleter(cursorPosition, "user");
|
messageInput.openCompleter(cursorPosition, "user");
|
||||||
popup.open();
|
popup.open();
|
||||||
|
@ -188,7 +188,7 @@ Rectangle {
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TimelineManager.timeline.input.send();
|
room.input.send();
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
} else if (event.key == Qt.Key_Tab) {
|
} else if (event.key == Qt.Key_Tab) {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
|
@ -223,11 +223,11 @@ Rectangle {
|
||||||
} else if (event.key == Qt.Key_Up && event.modifiers == Qt.NoModifier) {
|
} else if (event.key == Qt.Key_Up && event.modifiers == Qt.NoModifier) {
|
||||||
if (cursorPosition == 0) {
|
if (cursorPosition == 0) {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
var idx = TimelineManager.timeline.edit ? TimelineManager.timeline.idToIndex(TimelineManager.timeline.edit) + 1 : 0;
|
var idx = room.edit ? room.idToIndex(room.edit) + 1 : 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
var id = TimelineManager.timeline.indexToId(idx);
|
var id = room.indexToId(idx);
|
||||||
if (!id || TimelineManager.timeline.getDump(id, "").isEditable) {
|
if (!id || room.getDump(id, "").isEditable) {
|
||||||
TimelineManager.timeline.edit = id;
|
room.edit = id;
|
||||||
cursorPosition = 0;
|
cursorPosition = 0;
|
||||||
Qt.callLater(positionCursorAtEnd);
|
Qt.callLater(positionCursorAtEnd);
|
||||||
break;
|
break;
|
||||||
|
@ -239,13 +239,13 @@ Rectangle {
|
||||||
positionCursorAtStart();
|
positionCursorAtStart();
|
||||||
}
|
}
|
||||||
} else if (event.key == Qt.Key_Down && event.modifiers == Qt.NoModifier) {
|
} else if (event.key == Qt.Key_Down && event.modifiers == Qt.NoModifier) {
|
||||||
if (cursorPosition == messageInput.length && TimelineManager.timeline.edit) {
|
if (cursorPosition == messageInput.length && room.edit) {
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
var idx = TimelineManager.timeline.idToIndex(TimelineManager.timeline.edit) - 1;
|
var idx = room.idToIndex(room.edit) - 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
var id = TimelineManager.timeline.indexToId(idx);
|
var id = room.indexToId(idx);
|
||||||
if (!id || TimelineManager.timeline.getDump(id, "").isEditable) {
|
if (!id || room.getDump(id, "").isEditable) {
|
||||||
TimelineManager.timeline.edit = id;
|
room.edit = id;
|
||||||
Qt.callLater(positionCursorAtStart);
|
Qt.callLater(positionCursorAtStart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -260,14 +260,14 @@ Rectangle {
|
||||||
background: null
|
background: null
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onActiveTimelineChanged: {
|
onRoomChanged: {
|
||||||
messageInput.clear();
|
messageInput.clear();
|
||||||
messageInput.append(TimelineManager.timeline.input.text());
|
messageInput.append(room.input.text());
|
||||||
messageInput.completerTriggeredAt = -1;
|
messageInput.completerTriggeredAt = -1;
|
||||||
popup.completerName = "";
|
popup.completerName = "";
|
||||||
messageInput.forceActiveFocus();
|
messageInput.forceActiveFocus();
|
||||||
}
|
}
|
||||||
target: TimelineManager
|
target: timelineView
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
@ -292,14 +292,14 @@ Rectangle {
|
||||||
messageInput.text = newText;
|
messageInput.text = newText;
|
||||||
messageInput.cursorPosition = newText.length;
|
messageInput.cursorPosition = newText.length;
|
||||||
}
|
}
|
||||||
target: TimelineManager.timeline ? TimelineManager.timeline.input : null
|
target: room ? room.input : null
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
ignoreUnknownSignals: true
|
ignoreUnknownSignals: true
|
||||||
onReplyChanged: messageInput.forceActiveFocus()
|
onReplyChanged: messageInput.forceActiveFocus()
|
||||||
onEditChanged: messageInput.forceActiveFocus()
|
onEditChanged: messageInput.forceActiveFocus()
|
||||||
target: TimelineManager.timeline
|
target: room
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
@ -312,7 +312,7 @@ Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.MiddleButton
|
acceptedButtons: Qt.MiddleButton
|
||||||
cursorShape: Qt.IBeamCursor
|
cursorShape: Qt.IBeamCursor
|
||||||
onClicked: TimelineManager.timeline.input.paste(true)
|
onClicked: room.input.paste(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ Rectangle {
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: qsTr("Send")
|
ToolTip.text: qsTr("Send")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
TimelineManager.timeline.input.send();
|
room.input.send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ Rectangle {
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: TimelineManager.timeline ? (!TimelineManager.timeline.permissions.canSend(MtxEvent.TextMessage)) : false
|
visible: room ? (!room.permissions.canSend(MtxEvent.TextMessage)) : false
|
||||||
text: qsTr("You don't have permission to send messages in this room")
|
text: qsTr("You don't have permission to send messages in this room")
|
||||||
color: Nheko.colors.text
|
color: Nheko.colors.text
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
import "./delegates"
|
import "./delegates"
|
||||||
import "./emoji"
|
import "./emoji"
|
||||||
|
import Qt.labs.platform 1.1 as Platform
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.3
|
||||||
|
@ -22,7 +23,7 @@ ScrollView {
|
||||||
|
|
||||||
property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < parent.availableWidth) ? Settings.timelineMaxWidth : parent.availableWidth) - parent.padding * 2
|
property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < parent.availableWidth) ? Settings.timelineMaxWidth : parent.availableWidth) - parent.padding * 2
|
||||||
|
|
||||||
model: TimelineManager.timeline
|
model: room
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
pixelAligned: true
|
pixelAligned: true
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
@ -413,4 +414,141 @@ ScrollView {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Platform.Menu {
|
||||||
|
id: messageContextMenu
|
||||||
|
|
||||||
|
property string eventId
|
||||||
|
property string link
|
||||||
|
property string text
|
||||||
|
property int eventType
|
||||||
|
property bool isEncrypted
|
||||||
|
property bool isEditable
|
||||||
|
property bool isSender
|
||||||
|
|
||||||
|
function show(eventId_, eventType_, isSender_, isEncrypted_, isEditable_, link_, text_, showAt_) {
|
||||||
|
eventId = eventId_;
|
||||||
|
eventType = eventType_;
|
||||||
|
isEncrypted = isEncrypted_;
|
||||||
|
isEditable = isEditable_;
|
||||||
|
isSender = isSender_;
|
||||||
|
if (text_)
|
||||||
|
text = text_;
|
||||||
|
else
|
||||||
|
text = "";
|
||||||
|
if (link_)
|
||||||
|
link = link_;
|
||||||
|
else
|
||||||
|
link = "";
|
||||||
|
if (showAt_)
|
||||||
|
open(showAt_);
|
||||||
|
else
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.text
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("Copy")
|
||||||
|
onTriggered: Clipboard.text = messageContextMenu.text
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.link
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("Copy link location")
|
||||||
|
onTriggered: Clipboard.text = messageContextMenu.link
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
id: reactionOption
|
||||||
|
|
||||||
|
visible: room ? room.permissions.canSend(MtxEvent.Reaction) : false
|
||||||
|
text: qsTr("React")
|
||||||
|
onTriggered: emojiPopup.show(null, function(emoji) {
|
||||||
|
room.input.reaction(messageContextMenu.eventId, emoji);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: room ? room.permissions.canSend(MtxEvent.TextMessage) : false
|
||||||
|
text: qsTr("Reply")
|
||||||
|
onTriggered: room.replyAction(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.isEditable && (room ? room.permissions.canSend(MtxEvent.TextMessage) : false)
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("Edit")
|
||||||
|
onTriggered: room.editAction(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
text: qsTr("Read receipts")
|
||||||
|
onTriggered: room.readReceiptsAction(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker || messageContextMenu.eventType == MtxEvent.TextMessage || messageContextMenu.eventType == MtxEvent.LocationMessage || messageContextMenu.eventType == MtxEvent.EmoteMessage || messageContextMenu.eventType == MtxEvent.NoticeMessage
|
||||||
|
text: qsTr("Forward")
|
||||||
|
onTriggered: {
|
||||||
|
var forwardMess = forwardCompleterComponent.createObject(timelineRoot);
|
||||||
|
forwardMess.setMessageEventId(messageContextMenu.eventId);
|
||||||
|
forwardMess.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
text: qsTr("Mark as read")
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
text: qsTr("View raw message")
|
||||||
|
onTriggered: room.viewRawMessage(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
// TODO(Nico): Fix this still being iterated over, when using keyboard to select options
|
||||||
|
visible: messageContextMenu.isEncrypted
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("View decrypted raw message")
|
||||||
|
onTriggered: room.viewDecryptedRawMessage(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: (room ? room.permissions.canRedact() : false) || messageContextMenu.isSender
|
||||||
|
text: qsTr("Remove message")
|
||||||
|
onTriggered: room.redactEvent(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("Save as")
|
||||||
|
onTriggered: room.saveMedia(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("Open in external program")
|
||||||
|
onTriggered: room.openMedia(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform.MenuItem {
|
||||||
|
visible: messageContextMenu.eventId
|
||||||
|
enabled: visible
|
||||||
|
text: qsTr("Copy link to event")
|
||||||
|
onTriggered: room.copyLinkToEvent(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: forwardCompleterComponent
|
||||||
|
|
||||||
|
ForwardCompleter {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,8 +72,7 @@ Popup {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onCompletionSelected: {
|
onCompletionSelected: {
|
||||||
TimelineManager.setHistoryView(id);
|
Rooms.setCurrentRoom(id);
|
||||||
TimelineManager.highlightRoom(id);
|
|
||||||
quickSwitcher.close();
|
quickSwitcher.close();
|
||||||
}
|
}
|
||||||
onCountChanged: {
|
onCountChanged: {
|
||||||
|
|
|
@ -35,7 +35,7 @@ Flow {
|
||||||
ToolTip.text: modelData.users
|
ToolTip.text: modelData.users
|
||||||
onClicked: {
|
onClicked: {
|
||||||
console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + ". selfReactedEvent: " + modelData.selfReactedEvent);
|
console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + ". selfReactedEvent: " + modelData.selfReactedEvent);
|
||||||
TimelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key);
|
room.input.reaction(reactionFlow.eventId, modelData.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Row {
|
contentItem: Row {
|
||||||
|
|
|
@ -11,8 +11,6 @@ import im.nheko 1.0
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: replyPopup
|
id: replyPopup
|
||||||
|
|
||||||
property var room: TimelineManager.timeline
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: room && (room.reply || room.edit)
|
visible: room && (room.reply || room.edit)
|
||||||
// Height of child, plus margins, plus border
|
// Height of child, plus margins, plus border
|
||||||
|
|
|
@ -149,7 +149,7 @@ Page {
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: "selected"
|
name: "selected"
|
||||||
when: TimelineManager.timeline && model.roomId == TimelineManager.timeline.roomId()
|
when: Rooms.currentRoom && model.roomId == Rooms.currentRoom.roomId()
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: roomItem
|
target: roomItem
|
||||||
|
@ -165,18 +165,27 @@ Page {
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
onSingleTapped: roomContextMenu.show(model.roomId, model.tags)
|
onSingleTapped: {
|
||||||
|
if (!TimelineManager.isInvite) {
|
||||||
|
roomContextMenu.show(model.roomId, model.tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TapHandler {
|
||||||
|
onSingleTapped: Rooms.setCurrentRoom(model.roomId)
|
||||||
|
onLongPressed: {
|
||||||
|
if (!TimelineManager.isInvite) {
|
||||||
|
roomContextMenu.show(model.roomId, model.tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
id: hovered
|
id: hovered
|
||||||
}
|
}
|
||||||
|
|
||||||
TapHandler {
|
|
||||||
onSingleTapped: TimelineManager.setHistoryView(model.roomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: Nheko.paddingMedium
|
spacing: Nheko.paddingMedium
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -63,14 +63,6 @@ Page {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
|
||||||
id: forwardCompleterComponent
|
|
||||||
|
|
||||||
ForwardCompleter {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Ctrl+K"
|
sequence: "Ctrl+K"
|
||||||
onActivated: {
|
onActivated: {
|
||||||
|
@ -80,135 +72,6 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.Menu {
|
|
||||||
id: messageContextMenu
|
|
||||||
|
|
||||||
property string eventId
|
|
||||||
property string link
|
|
||||||
property string text
|
|
||||||
property int eventType
|
|
||||||
property bool isEncrypted
|
|
||||||
property bool isEditable
|
|
||||||
property bool isSender
|
|
||||||
|
|
||||||
function show(eventId_, eventType_, isSender_, isEncrypted_, isEditable_, link_, text_, showAt_) {
|
|
||||||
eventId = eventId_;
|
|
||||||
eventType = eventType_;
|
|
||||||
isEncrypted = isEncrypted_;
|
|
||||||
isEditable = isEditable_;
|
|
||||||
isSender = isSender_;
|
|
||||||
if (text_)
|
|
||||||
text = text_;
|
|
||||||
else
|
|
||||||
text = "";
|
|
||||||
if (link_)
|
|
||||||
link = link_;
|
|
||||||
else
|
|
||||||
link = "";
|
|
||||||
if (showAt_)
|
|
||||||
open(showAt_);
|
|
||||||
else
|
|
||||||
open();
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.text
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("Copy")
|
|
||||||
onTriggered: Clipboard.text = messageContextMenu.text
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.link
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("Copy link location")
|
|
||||||
onTriggered: Clipboard.text = messageContextMenu.link
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
id: reactionOption
|
|
||||||
|
|
||||||
visible: TimelineManager.timeline ? TimelineManager.timeline.permissions.canSend(MtxEvent.Reaction) : false
|
|
||||||
text: qsTr("React")
|
|
||||||
onTriggered: emojiPopup.show(null, function(emoji) {
|
|
||||||
TimelineManager.queueReactionMessage(messageContextMenu.eventId, emoji);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: TimelineManager.timeline ? TimelineManager.timeline.permissions.canSend(MtxEvent.TextMessage) : false
|
|
||||||
text: qsTr("Reply")
|
|
||||||
onTriggered: TimelineManager.timeline.replyAction(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.isEditable && (TimelineManager.timeline ? TimelineManager.timeline.permissions.canSend(MtxEvent.TextMessage) : false)
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("Edit")
|
|
||||||
onTriggered: TimelineManager.timeline.editAction(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
text: qsTr("Read receipts")
|
|
||||||
onTriggered: TimelineManager.timeline.readReceiptsAction(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker || messageContextMenu.eventType == MtxEvent.TextMessage || messageContextMenu.eventType == MtxEvent.LocationMessage || messageContextMenu.eventType == MtxEvent.EmoteMessage || messageContextMenu.eventType == MtxEvent.NoticeMessage
|
|
||||||
text: qsTr("Forward")
|
|
||||||
onTriggered: {
|
|
||||||
var forwardMess = forwardCompleterComponent.createObject(timelineRoot);
|
|
||||||
forwardMess.setMessageEventId(messageContextMenu.eventId);
|
|
||||||
forwardMess.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
text: qsTr("Mark as read")
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
text: qsTr("View raw message")
|
|
||||||
onTriggered: TimelineManager.timeline.viewRawMessage(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
// TODO(Nico): Fix this still being iterated over, when using keyboard to select options
|
|
||||||
visible: messageContextMenu.isEncrypted
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("View decrypted raw message")
|
|
||||||
onTriggered: TimelineManager.timeline.viewDecryptedRawMessage(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: (TimelineManager.timeline ? TimelineManager.timeline.permissions.canRedact() : false) || messageContextMenu.isSender
|
|
||||||
text: qsTr("Remove message")
|
|
||||||
onTriggered: TimelineManager.timeline.redactEvent(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("Save as")
|
|
||||||
onTriggered: TimelineManager.timeline.saveMedia(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("Open in external program")
|
|
||||||
onTriggered: TimelineManager.timeline.openMedia(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.MenuItem {
|
|
||||||
visible: messageContextMenu.eventId
|
|
||||||
enabled: visible
|
|
||||||
text: qsTr("Copy link to event")
|
|
||||||
onTriggered: TimelineManager.timeline.copyLinkToEvent(messageContextMenu.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: deviceVerificationDialog
|
id: deviceVerificationDialog
|
||||||
|
|
||||||
|
@ -233,16 +96,6 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: TimelineManager.timeline
|
|
||||||
onOpenRoomSettingsDialog: {
|
|
||||||
var roomSettings = roomSettingsComponent.createObject(timelineRoot, {
|
|
||||||
"roomSettings": settings
|
|
||||||
});
|
|
||||||
roomSettings.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: CallManager
|
target: CallManager
|
||||||
onNewInviteState: {
|
onNewInviteState: {
|
||||||
|
|
|
@ -31,7 +31,7 @@ ImageButton {
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (model.state == MtxEvent.Read)
|
if (model.state == MtxEvent.Read)
|
||||||
TimelineManager.timeline.readReceiptsAction(model.id);
|
room.readReceiptsAction(model.id);
|
||||||
|
|
||||||
}
|
}
|
||||||
image: {
|
image: {
|
||||||
|
|
|
@ -18,8 +18,10 @@ import im.nheko.EmojiModel 1.0
|
||||||
Item {
|
Item {
|
||||||
id: timelineView
|
id: timelineView
|
||||||
|
|
||||||
|
property var room: null
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
visible: !TimelineManager.timeline && !TimelineManager.isInitialSync
|
visible: !room && !TimelineManager.isInitialSync
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: qsTr("No room open")
|
text: qsTr("No room open")
|
||||||
font.pointSize: 24
|
font.pointSize: 24
|
||||||
|
@ -38,7 +40,7 @@ Item {
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: timelineLayout
|
id: timelineLayout
|
||||||
|
|
||||||
visible: TimelineManager.timeline != null
|
visible: room != null
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
@ -69,11 +71,11 @@ Item {
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
function onActiveTimelineChanged() {
|
function onRoomChanged() {
|
||||||
stackLayout.currentIndex = 0;
|
stackLayout.currentIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
target: TimelineManager
|
target: timelineView
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageView {
|
MessageView {
|
||||||
|
@ -125,7 +127,17 @@ Item {
|
||||||
|
|
||||||
NhekoDropArea {
|
NhekoDropArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
roomid: TimelineManager.timeline ? TimelineManager.timeline.roomId() : ""
|
roomid: room ? room.roomId() : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: room
|
||||||
|
onOpenRoomSettingsDialog: {
|
||||||
|
var roomSettings = roomSettingsComponent.createObject(timelineRoot, {
|
||||||
|
"roomSettings": settings
|
||||||
|
});
|
||||||
|
roomSettings.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,6 @@ import im.nheko 1.0
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: topBar
|
id: topBar
|
||||||
|
|
||||||
property var room: TimelineManager.timeline
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: topLayout.height + Nheko.paddingMedium * 2
|
implicitHeight: topLayout.height + Nheko.paddingMedium * 2
|
||||||
z: 3
|
z: 3
|
||||||
|
@ -20,7 +18,7 @@ Rectangle {
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
onSingleTapped: {
|
onSingleTapped: {
|
||||||
TimelineManager.timeline.openRoomSettings();
|
room.openRoomSettings();
|
||||||
eventPoint.accepted = true;
|
eventPoint.accepted = true;
|
||||||
}
|
}
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
@ -61,7 +59,7 @@ Rectangle {
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: room ? room.roomAvatarUrl.replace("mxc://", "image://MxcImage/") : ""
|
url: room ? room.roomAvatarUrl.replace("mxc://", "image://MxcImage/") : ""
|
||||||
displayName: room ? room.roomName : qsTr("No room selected")
|
displayName: room ? room.roomName : qsTr("No room selected")
|
||||||
onClicked: TimelineManager.timeline.openRoomSettings()
|
onClicked: room.openRoomSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@ -101,24 +99,24 @@ Rectangle {
|
||||||
id: roomOptionsMenu
|
id: roomOptionsMenu
|
||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
visible: TimelineManager.timeline ? TimelineManager.timeline.permissions.canInvite() : false
|
visible: room ? room.permissions.canInvite() : false
|
||||||
text: qsTr("Invite users")
|
text: qsTr("Invite users")
|
||||||
onTriggered: TimelineManager.openInviteUsersDialog()
|
onTriggered: TimelineManager.openInviteUsersDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: qsTr("Members")
|
text: qsTr("Members")
|
||||||
onTriggered: TimelineManager.openMemberListDialog()
|
onTriggered: TimelineManager.openMemberListDialog(room.roomId())
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: qsTr("Leave room")
|
text: qsTr("Leave room")
|
||||||
onTriggered: TimelineManager.openLeaveRoomDialog()
|
onTriggered: TimelineManager.openLeaveRoomDialog(room.roomId())
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: qsTr("Settings")
|
text: qsTr("Settings")
|
||||||
onTriggered: TimelineManager.timeline.openRoomSettings()
|
onTriggered: room.openRoomSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ import QtQuick.Layouts 1.2
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property var room: TimelineManager.timeline
|
|
||||||
|
|
||||||
implicitHeight: Math.max(fontMetrics.height * 1.2, typingDisplay.height)
|
implicitHeight: Math.max(fontMetrics.height * 1.2, typingDisplay.height)
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
onSingleTapped: TimelineManager.timeline.saveMedia(model.data.id)
|
onSingleTapped: room.saveMedia(model.data.id)
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ Item {
|
||||||
roleValue: MtxEvent.PowerLevels
|
roleValue: MtxEvent.PowerLevels
|
||||||
|
|
||||||
NoticeMessage {
|
NoticeMessage {
|
||||||
text: TimelineManager.timeline.formatPowerLevelEvent(model.data.id)
|
text: room.formatPowerLevelEvent(model.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ Item {
|
||||||
roleValue: MtxEvent.RoomJoinRules
|
roleValue: MtxEvent.RoomJoinRules
|
||||||
|
|
||||||
NoticeMessage {
|
NoticeMessage {
|
||||||
text: TimelineManager.timeline.formatJoinRuleEvent(model.data.id)
|
text: room.formatJoinRuleEvent(model.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ Item {
|
||||||
roleValue: MtxEvent.RoomHistoryVisibility
|
roleValue: MtxEvent.RoomHistoryVisibility
|
||||||
|
|
||||||
NoticeMessage {
|
NoticeMessage {
|
||||||
text: TimelineManager.timeline.formatHistoryVisibilityEvent(model.data.id)
|
text: room.formatHistoryVisibilityEvent(model.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ Item {
|
||||||
roleValue: MtxEvent.RoomGuestAccess
|
roleValue: MtxEvent.RoomGuestAccess
|
||||||
|
|
||||||
NoticeMessage {
|
NoticeMessage {
|
||||||
text: TimelineManager.timeline.formatGuestAccessEvent(model.data.id)
|
text: room.formatGuestAccessEvent(model.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ Item {
|
||||||
roleValue: MtxEvent.Member
|
roleValue: MtxEvent.Member
|
||||||
|
|
||||||
NoticeMessage {
|
NoticeMessage {
|
||||||
text: TimelineManager.timeline.formatMemberEvent(model.data.id)
|
text: room.formatMemberEvent(model.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ Rectangle {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
switch (button.state) {
|
switch (button.state) {
|
||||||
case "":
|
case "":
|
||||||
TimelineManager.timeline.cacheMedia(model.data.id);
|
room.cacheMedia(model.data.id);
|
||||||
break;
|
break;
|
||||||
case "stopped":
|
case "stopped":
|
||||||
media.play();
|
media.play();
|
||||||
|
@ -174,7 +174,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: TimelineManager.timeline
|
target: room
|
||||||
onMediaCached: {
|
onMediaCached: {
|
||||||
if (mxcUrl == model.data.url) {
|
if (mxcUrl == model.data.url) {
|
||||||
media.source = cacheUrl;
|
media.source = cacheUrl;
|
||||||
|
|
|
@ -17,7 +17,7 @@ ImageButton {
|
||||||
|
|
||||||
image: ":/icons/icons/ui/smile.png"
|
image: ":/icons/icons/ui/smile.png"
|
||||||
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, function(emoji) {
|
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, function(emoji) {
|
||||||
TimelineManager.queueReactionMessage(event_id, emoji);
|
room.input.reaction(event_id, emoji);
|
||||||
TimelineManager.focusMessageInput();
|
TimelineManager.focusMessageInput();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ Rectangle {
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: CallManager.callParty
|
displayName: CallManager.callParty
|
||||||
onClicked: TimelineManager.openImageOverlay(TimelineManager.timeline.avatarUrl(userid), TimelineManager.timeline.data.id)
|
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
|
|
@ -42,7 +42,7 @@ Rectangle {
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: CallManager.callParty
|
displayName: CallManager.callParty
|
||||||
onClicked: TimelineManager.openImageOverlay(TimelineManager.timeline.avatarUrl(userid), TimelineManager.timeline.data.id)
|
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
|
|
@ -45,7 +45,7 @@ Popup {
|
||||||
Layout.leftMargin: 8
|
Layout.leftMargin: 8
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: qsTr("Place a call to %1?").arg(TimelineManager.timeline.roomName)
|
text: qsTr("Place a call to %1?").arg(room.roomName)
|
||||||
color: Nheko.colors.windowText
|
color: Nheko.colors.windowText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +77,9 @@ Popup {
|
||||||
Layout.rightMargin: cameraCombo.visible ? 16 : 64
|
Layout.rightMargin: cameraCombo.visible ? 16 : 64
|
||||||
width: Nheko.avatarSize
|
width: Nheko.avatarSize
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: TimelineManager.timeline.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: TimelineManager.timeline.roomName
|
displayName: room.roomName
|
||||||
onClicked: TimelineManager.openImageOverlay(TimelineManager.timeline.avatarUrl(userid), TimelineManager.timeline.data.id)
|
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -88,7 +88,7 @@ Popup {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (buttonLayout.validateMic()) {
|
if (buttonLayout.validateMic()) {
|
||||||
Settings.microphone = micCombo.currentText;
|
Settings.microphone = micCombo.currentText;
|
||||||
CallManager.sendInvite(TimelineManager.timeline.roomId(), CallType.VOICE);
|
CallManager.sendInvite(room.roomId(), CallType.VOICE);
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ Popup {
|
||||||
if (buttonLayout.validateMic()) {
|
if (buttonLayout.validateMic()) {
|
||||||
Settings.microphone = micCombo.currentText;
|
Settings.microphone = micCombo.currentText;
|
||||||
Settings.camera = cameraCombo.currentText;
|
Settings.camera = cameraCombo.currentText;
|
||||||
CallManager.sendInvite(TimelineManager.timeline.roomId(), CallType.VIDEO);
|
CallManager.sendInvite(room.roomId(), CallType.VIDEO);
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ Popup {
|
||||||
Layout.leftMargin: 8
|
Layout.leftMargin: 8
|
||||||
Layout.rightMargin: 8
|
Layout.rightMargin: 8
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
text: qsTr("Share desktop with %1?").arg(TimelineManager.timeline.roomName)
|
text: qsTr("Share desktop with %1?").arg(room.roomName)
|
||||||
color: Nheko.colors.windowText
|
color: Nheko.colors.windowText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ Popup {
|
||||||
Settings.screenSharePiP = pipCheckBox.checked;
|
Settings.screenSharePiP = pipCheckBox.checked;
|
||||||
Settings.screenShareRemoteVideo = remoteVideoCheckBox.checked;
|
Settings.screenShareRemoteVideo = remoteVideoCheckBox.checked;
|
||||||
Settings.screenShareHideCursor = hideCursorCheckBox.checked;
|
Settings.screenShareHideCursor = hideCursorCheckBox.checked;
|
||||||
CallManager.sendInvite(TimelineManager.timeline.roomId(), CallType.SCREEN, windowCombo.currentIndex);
|
CallManager.sendInvite(room.roomId(), CallType.SCREEN, windowCombo.currentIndex);
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,8 +215,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
|
||||||
this->current_room_ = room_id;
|
this->current_room_ = room_id;
|
||||||
});
|
});
|
||||||
connect(room_list_, &RoomList::roomChanged, splitter, &Splitter::showChatView);
|
connect(room_list_, &RoomList::roomChanged, splitter, &Splitter::showChatView);
|
||||||
connect(
|
|
||||||
room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
|
|
||||||
|
|
||||||
connect(room_list_, &RoomList::acceptInvite, this, [this](const QString &room_id) {
|
connect(room_list_, &RoomList::acceptInvite, this, [this](const QString &room_id) {
|
||||||
joinRoom(room_id);
|
joinRoom(room_id);
|
||||||
|
@ -982,7 +980,7 @@ ChatPage::leaveRoom(const QString &room_id)
|
||||||
void
|
void
|
||||||
ChatPage::changeRoom(const QString &room_id)
|
ChatPage::changeRoom(const QString &room_id)
|
||||||
{
|
{
|
||||||
view_manager_->setHistoryView(room_id);
|
view_manager_->rooms()->setCurrentRoom(room_id);
|
||||||
room_list_->highlightSelectedRoom(room_id);
|
room_list_->highlightSelectedRoom(room_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,7 +1395,8 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
|
||||||
|
|
||||||
if (sigil1 == "u") {
|
if (sigil1 == "u") {
|
||||||
if (action.isEmpty()) {
|
if (action.isEmpty()) {
|
||||||
view_manager_->activeTimeline()->openUserProfile(mxid1);
|
if (auto t = view_manager_->rooms()->currentRoom())
|
||||||
|
t->openUserProfile(mxid1);
|
||||||
} else if (action == "chat") {
|
} else if (action == "chat") {
|
||||||
this->startChat(mxid1);
|
this->startChat(mxid1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -508,8 +508,7 @@ InputBar::command(QString command, QString args)
|
||||||
} else if (command == "react") {
|
} else if (command == "react") {
|
||||||
auto eventId = room->reply();
|
auto eventId = room->reply();
|
||||||
if (!eventId.isEmpty())
|
if (!eventId.isEmpty())
|
||||||
ChatPage::instance()->timelineManager()->queueReactionMessage(
|
reaction(eventId, args.trimmed());
|
||||||
eventId, args.trimmed());
|
|
||||||
} else if (command == "join") {
|
} else if (command == "join") {
|
||||||
ChatPage::instance()->joinRoom(args);
|
ChatPage::instance()->joinRoom(args);
|
||||||
} else if (command == "part" || command == "leave") {
|
} else if (command == "part" || command == "leave") {
|
||||||
|
@ -715,3 +714,35 @@ InputBar::stopTyping()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputBar::reaction(const QString &reactedEvent, const QString &reactionKey)
|
||||||
|
{
|
||||||
|
auto reactions = room->reactions(reactedEvent.toStdString());
|
||||||
|
|
||||||
|
QString selfReactedEvent;
|
||||||
|
for (const auto &reaction : reactions) {
|
||||||
|
if (reactionKey == reaction.key_) {
|
||||||
|
selfReactedEvent = reaction.selfReactedEvent_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfReactedEvent.startsWith("m"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If selfReactedEvent is empty, that means we haven't previously reacted
|
||||||
|
if (selfReactedEvent.isEmpty()) {
|
||||||
|
mtx::events::msg::Reaction reaction;
|
||||||
|
mtx::common::Relation rel;
|
||||||
|
rel.rel_type = mtx::common::RelationType::Annotation;
|
||||||
|
rel.event_id = reactedEvent.toStdString();
|
||||||
|
rel.key = reactionKey.toStdString();
|
||||||
|
reaction.relations.relations.push_back(rel);
|
||||||
|
|
||||||
|
room->sendMessageEvent(reaction, mtx::events::EventType::Reaction);
|
||||||
|
// Otherwise, we have previously reacted and the reaction should be redacted
|
||||||
|
} else {
|
||||||
|
room->redactEvent(selfReactedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ public slots:
|
||||||
void message(QString body,
|
void message(QString body,
|
||||||
MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED,
|
MarkdownOverride useMarkdown = MarkdownOverride::NOT_SPECIFIED,
|
||||||
bool rainbowify = false);
|
bool rainbowify = false);
|
||||||
|
void reaction(const QString &reactedEvent, const QString &reactionKey);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void startTyping();
|
void startTyping();
|
||||||
|
|
|
@ -341,6 +341,8 @@ RoomlistModel::clear()
|
||||||
models.clear();
|
models.clear();
|
||||||
invites.clear();
|
invites.clear();
|
||||||
roomids.clear();
|
roomids.clear();
|
||||||
|
currentRoom_ = nullptr;
|
||||||
|
emit currentRoomChanged();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,6 +392,17 @@ RoomlistModel::leave(QString roomid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RoomlistModel::setCurrentRoom(QString roomid)
|
||||||
|
{
|
||||||
|
nhlog::ui()->debug("Trying to switch to: {}", roomid.toStdString());
|
||||||
|
if (models.contains(roomid)) {
|
||||||
|
currentRoom_ = models.value(roomid);
|
||||||
|
emit currentRoomChanged();
|
||||||
|
nhlog::ui()->debug("Switched to: {}", roomid.toStdString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum NotificationImportance : short
|
enum NotificationImportance : short
|
||||||
{
|
{
|
||||||
|
@ -463,6 +476,11 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
|
||||||
invalidate();
|
invalidate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(roomlistmodel,
|
||||||
|
&RoomlistModel::currentRoomChanged,
|
||||||
|
this,
|
||||||
|
&FilteredRoomlistModel::currentRoomChanged);
|
||||||
|
|
||||||
sort(0);
|
sort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
|
|
||||||
#include <mtx/responses/sync.hpp>
|
#include <mtx/responses/sync.hpp>
|
||||||
|
|
||||||
class TimelineModel;
|
#include "TimelineModel.h"
|
||||||
|
|
||||||
class TimelineViewManager;
|
class TimelineViewManager;
|
||||||
|
|
||||||
class RoomlistModel : public QAbstractListModel
|
class RoomlistModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged)
|
||||||
public:
|
public:
|
||||||
enum Roles
|
enum Roles
|
||||||
{
|
{
|
||||||
|
@ -69,12 +71,15 @@ public slots:
|
||||||
void acceptInvite(QString roomid);
|
void acceptInvite(QString roomid);
|
||||||
void declineInvite(QString roomid);
|
void declineInvite(QString roomid);
|
||||||
void leave(QString roomid);
|
void leave(QString roomid);
|
||||||
|
TimelineModel *currentRoom() const { return currentRoom_.get(); }
|
||||||
|
void setCurrentRoom(QString roomid);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateReadStatus(const std::map<QString, bool> roomReadStatus_);
|
void updateReadStatus(const std::map<QString, bool> roomReadStatus_);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void totalUnreadMessageCountUpdated(int unreadMessages);
|
void totalUnreadMessageCountUpdated(int unreadMessages);
|
||||||
|
void currentRoomChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
|
void addRoom(const QString &room_id, bool suppressInsertNotification = false);
|
||||||
|
@ -85,12 +90,15 @@ private:
|
||||||
QHash<QString, QSharedPointer<TimelineModel>> models;
|
QHash<QString, QSharedPointer<TimelineModel>> models;
|
||||||
std::map<QString, bool> roomReadStatus;
|
std::map<QString, bool> roomReadStatus;
|
||||||
|
|
||||||
|
QSharedPointer<TimelineModel> currentRoom_;
|
||||||
|
|
||||||
friend class FilteredRoomlistModel;
|
friend class FilteredRoomlistModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilteredRoomlistModel : public QSortFilterProxyModel
|
class FilteredRoomlistModel : public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged)
|
||||||
public:
|
public:
|
||||||
FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
|
FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
|
||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
|
@ -107,6 +115,12 @@ public slots:
|
||||||
QStringList tags();
|
QStringList tags();
|
||||||
void toggleTag(QString roomid, QString tag, bool on);
|
void toggleTag(QString roomid, QString tag, bool on);
|
||||||
|
|
||||||
|
TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); }
|
||||||
|
void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void currentRoomChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
short int calculateImportance(const QModelIndex &idx) const;
|
short int calculateImportance(const QModelIndex &idx) const;
|
||||||
RoomlistModel *roomlistmodel;
|
RoomlistModel *roomlistmodel;
|
||||||
|
|
|
@ -133,7 +133,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
||||||
, colorImgProvider(new ColorImageProvider())
|
, colorImgProvider(new ColorImageProvider())
|
||||||
, blurhashProvider(new BlurhashProvider())
|
, blurhashProvider(new BlurhashProvider())
|
||||||
, callManager_(callManager)
|
, callManager_(callManager)
|
||||||
, rooms(new RoomlistModel(this))
|
, rooms_(new RoomlistModel(this))
|
||||||
{
|
{
|
||||||
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
|
qRegisterMetaType<mtx::events::msg::KeyVerificationAccept>();
|
||||||
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
|
qRegisterMetaType<mtx::events::msg::KeyVerificationCancel>();
|
||||||
|
@ -193,7 +193,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
||||||
});
|
});
|
||||||
qmlRegisterSingletonType<RoomlistModel>(
|
qmlRegisterSingletonType<RoomlistModel>(
|
||||||
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||||
return new FilteredRoomlistModel(self->rooms);
|
return new FilteredRoomlistModel(self->rooms_);
|
||||||
});
|
});
|
||||||
qmlRegisterSingletonType<UserSettings>(
|
qmlRegisterSingletonType<UserSettings>(
|
||||||
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
"im.nheko", 1, 0, "Settings", [](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||||
|
@ -320,9 +320,9 @@ TimelineViewManager::setVideoCallItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::sync(const mtx::responses::Rooms &rooms_)
|
TimelineViewManager::sync(const mtx::responses::Rooms &rooms_res)
|
||||||
{
|
{
|
||||||
this->rooms->sync(rooms_);
|
this->rooms_->sync(rooms_res);
|
||||||
|
|
||||||
if (isInitialSync_) {
|
if (isInitialSync_) {
|
||||||
this->isInitialSync_ = false;
|
this->isInitialSync_ = false;
|
||||||
|
@ -330,37 +330,17 @@ TimelineViewManager::sync(const mtx::responses::Rooms &rooms_)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::setHistoryView(const QString &room_id)
|
|
||||||
{
|
|
||||||
nhlog::ui()->info("Trying to activate room {}", room_id.toStdString());
|
|
||||||
|
|
||||||
if (auto room = rooms->getRoomById(room_id)) {
|
|
||||||
timeline_ = room.get();
|
|
||||||
emit activeTimelineChanged(timeline_);
|
|
||||||
container->setFocus();
|
|
||||||
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::highlightRoom(const QString &room_id)
|
|
||||||
{
|
|
||||||
ChatPage::instance()->highlightRoom(room_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
|
TimelineViewManager::showEvent(const QString &room_id, const QString &event_id)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(room_id)) {
|
if (auto room = rooms_->getRoomById(room_id)) {
|
||||||
if (timeline_ != room) {
|
if (rooms_->currentRoom() != room) {
|
||||||
timeline_ = room.get();
|
rooms_->setCurrentRoom(room_id);
|
||||||
emit activeTimelineChanged(timeline_);
|
|
||||||
container->setFocus();
|
container->setFocus();
|
||||||
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
nhlog::ui()->info("Activated room {}", room_id.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
timeline_->showEvent(event_id);
|
room->showEvent(event_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,17 +375,20 @@ TimelineViewManager::openImageOverlayInternal(QString eventId, QImage img)
|
||||||
|
|
||||||
auto imgDialog = new dialogs::ImageOverlay(pixmap);
|
auto imgDialog = new dialogs::ImageOverlay(pixmap);
|
||||||
imgDialog->showFullScreen();
|
imgDialog->showFullScreen();
|
||||||
connect(imgDialog, &dialogs::ImageOverlay::saving, timeline_, [this, eventId, imgDialog]() {
|
|
||||||
// hide the overlay while presenting the save dialog for better
|
|
||||||
// cross platform support.
|
|
||||||
imgDialog->hide();
|
|
||||||
|
|
||||||
if (!timeline_->saveMedia(eventId)) {
|
auto room = rooms_->currentRoom();
|
||||||
imgDialog->show();
|
connect(
|
||||||
} else {
|
imgDialog, &dialogs::ImageOverlay::saving, room, [this, eventId, imgDialog, room]() {
|
||||||
imgDialog->close();
|
// hide the overlay while presenting the save dialog for better
|
||||||
}
|
// cross platform support.
|
||||||
});
|
imgDialog->hide();
|
||||||
|
|
||||||
|
if (!room->saveMedia(eventId)) {
|
||||||
|
imgDialog->show();
|
||||||
|
} else {
|
||||||
|
imgDialog->close();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -415,14 +398,14 @@ TimelineViewManager::openInviteUsersDialog()
|
||||||
[this](const QStringList &invitees) { emit inviteUsers(invitees); });
|
[this](const QStringList &invitees) { emit inviteUsers(invitees); });
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
TimelineViewManager::openMemberListDialog() const
|
TimelineViewManager::openMemberListDialog(QString roomid) const
|
||||||
{
|
{
|
||||||
MainWindow::instance()->openMemberListDialog(timeline_->roomId());
|
MainWindow::instance()->openMemberListDialog(roomid);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
TimelineViewManager::openLeaveRoomDialog() const
|
TimelineViewManager::openLeaveRoomDialog(QString roomid) const
|
||||||
{
|
{
|
||||||
MainWindow::instance()->openLeaveRoomDialog(timeline_->roomId());
|
MainWindow::instance()->openLeaveRoomDialog(roomid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -439,7 +422,7 @@ TimelineViewManager::verifyUser(QString userid)
|
||||||
room_members.end(),
|
room_members.end(),
|
||||||
(userid).toStdString()) != room_members.end()) {
|
(userid).toStdString()) != room_members.end()) {
|
||||||
if (auto model =
|
if (auto model =
|
||||||
rooms->getRoomById(QString::fromStdString(room_id))) {
|
rooms_->getRoomById(QString::fromStdString(room_id))) {
|
||||||
auto flow =
|
auto flow =
|
||||||
DeviceVerificationFlow::InitiateUserVerification(
|
DeviceVerificationFlow::InitiateUserVerification(
|
||||||
this, model.data(), userid);
|
this, model.data(), userid);
|
||||||
|
@ -485,7 +468,7 @@ void
|
||||||
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
TimelineViewManager::updateReadReceipts(const QString &room_id,
|
||||||
const std::vector<QString> &event_ids)
|
const std::vector<QString> &event_ids)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(room_id)) {
|
if (auto room = rooms_->getRoomById(room_id)) {
|
||||||
room->markEventsAsRead(event_ids);
|
room->markEventsAsRead(event_ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,7 +476,7 @@ TimelineViewManager::updateReadReceipts(const QString &room_id,
|
||||||
void
|
void
|
||||||
TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::string &session_id)
|
TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::string &session_id)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(QString::fromStdString(room_id))) {
|
if (auto room = rooms_->getRoomById(QString::fromStdString(room_id))) {
|
||||||
room->receivedSessionKey(session_id);
|
room->receivedSessionKey(session_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,7 +484,7 @@ TimelineViewManager::receivedSessionKey(const std::string &room_id, const std::s
|
||||||
void
|
void
|
||||||
TimelineViewManager::initializeRoomlist()
|
TimelineViewManager::initializeRoomlist()
|
||||||
{
|
{
|
||||||
rooms->initializeRooms();
|
rooms_->initializeRooms();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -509,51 +492,17 @@ TimelineViewManager::queueReply(const QString &roomid,
|
||||||
const QString &repliedToEvent,
|
const QString &repliedToEvent,
|
||||||
const QString &replyBody)
|
const QString &replyBody)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(roomid)) {
|
if (auto room = rooms_->getRoomById(roomid)) {
|
||||||
room->setReply(repliedToEvent);
|
room->setReply(repliedToEvent);
|
||||||
room->input()->message(replyBody);
|
room->input()->message(replyBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QString &reactionKey)
|
|
||||||
{
|
|
||||||
if (!timeline_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto reactions = timeline_->reactions(reactedEvent.toStdString());
|
|
||||||
|
|
||||||
QString selfReactedEvent;
|
|
||||||
for (const auto &reaction : reactions) {
|
|
||||||
if (reactionKey == reaction.key_) {
|
|
||||||
selfReactedEvent = reaction.selfReactedEvent_;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selfReactedEvent.startsWith("m"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If selfReactedEvent is empty, that means we haven't previously reacted
|
|
||||||
if (selfReactedEvent.isEmpty()) {
|
|
||||||
mtx::events::msg::Reaction reaction;
|
|
||||||
mtx::common::Relation rel;
|
|
||||||
rel.rel_type = mtx::common::RelationType::Annotation;
|
|
||||||
rel.event_id = reactedEvent.toStdString();
|
|
||||||
rel.key = reactionKey.toStdString();
|
|
||||||
reaction.relations.relations.push_back(rel);
|
|
||||||
|
|
||||||
timeline_->sendMessageEvent(reaction, mtx::events::EventType::Reaction);
|
|
||||||
// Otherwise, we have previously reacted and the reaction should be redacted
|
|
||||||
} else {
|
|
||||||
timeline_->redactEvent(selfReactedEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallInvite &callInvite)
|
const mtx::events::msg::CallInvite &callInvite)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(roomid))
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
room->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
|
room->sendMessageEvent(callInvite, mtx::events::EventType::CallInvite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,7 +510,7 @@ void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallCandidates &callCandidates)
|
const mtx::events::msg::CallCandidates &callCandidates)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(roomid))
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
room->sendMessageEvent(callCandidates, mtx::events::EventType::CallCandidates);
|
room->sendMessageEvent(callCandidates, mtx::events::EventType::CallCandidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +518,7 @@ void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallAnswer &callAnswer)
|
const mtx::events::msg::CallAnswer &callAnswer)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(roomid))
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
room->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
|
room->sendMessageEvent(callAnswer, mtx::events::EventType::CallAnswer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,7 +526,7 @@ void
|
||||||
TimelineViewManager::queueCallMessage(const QString &roomid,
|
TimelineViewManager::queueCallMessage(const QString &roomid,
|
||||||
const mtx::events::msg::CallHangUp &callHangUp)
|
const mtx::events::msg::CallHangUp &callHangUp)
|
||||||
{
|
{
|
||||||
if (auto room = rooms->getRoomById(roomid))
|
if (auto room = rooms_->getRoomById(roomid))
|
||||||
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
room->sendMessageEvent(callHangUp, mtx::events::EventType::CallHangUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +578,7 @@ void
|
||||||
TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents *e,
|
TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEvents *e,
|
||||||
QString roomId)
|
QString roomId)
|
||||||
{
|
{
|
||||||
auto room = rooms->getRoomById(roomId);
|
auto room = rooms_->getRoomById(roomId);
|
||||||
auto content = mtx::accessors::url(*e);
|
auto content = mtx::accessors::url(*e);
|
||||||
std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
|
std::optional<mtx::crypto::EncryptedFile> encryptionInfo = mtx::accessors::file(*e);
|
||||||
|
|
||||||
|
@ -672,7 +621,7 @@ TimelineViewManager::forwardMessageToRoom(mtx::events::collections::TimelineEven
|
||||||
ev.content.url = url;
|
ev.content.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto room = rooms->getRoomById(roomId)) {
|
if (auto room = rooms_->getRoomById(roomId)) {
|
||||||
removeReplyFallback(ev);
|
removeReplyFallback(ev);
|
||||||
ev.content.relations.relations
|
ev.content.relations.relations
|
||||||
.clear();
|
.clear();
|
||||||
|
|
|
@ -35,8 +35,6 @@ class TimelineViewManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(
|
|
||||||
TimelineModel *timeline MEMBER timeline_ READ activeTimeline NOTIFY activeTimelineChanged)
|
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
|
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
|
@ -53,14 +51,8 @@ public:
|
||||||
MxcImageProvider *imageProvider() { return imgProvider; }
|
MxcImageProvider *imageProvider() { return imgProvider; }
|
||||||
CallManager *callManager() { return callManager_; }
|
CallManager *callManager() { return callManager_; }
|
||||||
|
|
||||||
void clearAll()
|
void clearAll() { rooms_->clear(); }
|
||||||
{
|
|
||||||
timeline_ = nullptr;
|
|
||||||
emit activeTimelineChanged(nullptr);
|
|
||||||
rooms->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
|
|
||||||
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
|
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
|
||||||
bool isNarrowView() const { return isNarrowView_; }
|
bool isNarrowView() const { return isNarrowView_; }
|
||||||
bool isWindowFocused() const { return isWindowFocused_; }
|
bool isWindowFocused() const { return isWindowFocused_; }
|
||||||
|
@ -74,8 +66,8 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void focusMessageInput();
|
Q_INVOKABLE void focusMessageInput();
|
||||||
Q_INVOKABLE void openInviteUsersDialog();
|
Q_INVOKABLE void openInviteUsersDialog();
|
||||||
Q_INVOKABLE void openMemberListDialog() const;
|
Q_INVOKABLE void openMemberListDialog(QString roomid) const;
|
||||||
Q_INVOKABLE void openLeaveRoomDialog() const;
|
Q_INVOKABLE void openLeaveRoomDialog(QString roomid) const;
|
||||||
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
|
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
|
||||||
|
|
||||||
void verifyUser(QString userid);
|
void verifyUser(QString userid);
|
||||||
|
@ -107,20 +99,13 @@ public slots:
|
||||||
emit focusChanged();
|
emit focusChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHistoryView(const QString &room_id);
|
|
||||||
void highlightRoom(const QString &room_id);
|
|
||||||
void showEvent(const QString &room_id, const QString &event_id);
|
void showEvent(const QString &room_id, const QString &event_id);
|
||||||
void focusTimeline();
|
void focusTimeline();
|
||||||
TimelineModel *getHistoryView(const QString &room_id)
|
|
||||||
{
|
|
||||||
return rooms->getRoomById(room_id).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateColorPalette();
|
void updateColorPalette();
|
||||||
void queueReply(const QString &roomid,
|
void queueReply(const QString &roomid,
|
||||||
const QString &repliedToEvent,
|
const QString &repliedToEvent,
|
||||||
const QString &replyBody);
|
const QString &replyBody);
|
||||||
void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey);
|
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallInvite &);
|
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallInvite &);
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallCandidates &);
|
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallCandidates &);
|
||||||
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallAnswer &);
|
void queueCallMessage(const QString &roomid, const mtx::events::msg::CallAnswer &);
|
||||||
|
@ -147,6 +132,8 @@ public slots:
|
||||||
QObject *completerFor(QString completerName, QString roomId = "");
|
QObject *completerFor(QString completerName, QString roomId = "");
|
||||||
void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
|
void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
|
||||||
|
|
||||||
|
RoomlistModel *rooms() { return rooms_; }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void openImageOverlayInternal(QString eventId, QImage img);
|
void openImageOverlayInternal(QString eventId, QImage img);
|
||||||
|
|
||||||
|
@ -162,14 +149,13 @@ private:
|
||||||
ColorImageProvider *colorImgProvider;
|
ColorImageProvider *colorImgProvider;
|
||||||
BlurhashProvider *blurhashProvider;
|
BlurhashProvider *blurhashProvider;
|
||||||
|
|
||||||
TimelineModel *timeline_ = nullptr;
|
|
||||||
CallManager *callManager_ = nullptr;
|
CallManager *callManager_ = nullptr;
|
||||||
|
|
||||||
bool isInitialSync_ = true;
|
bool isInitialSync_ = true;
|
||||||
bool isNarrowView_ = false;
|
bool isNarrowView_ = false;
|
||||||
bool isWindowFocused_ = false;
|
bool isWindowFocused_ = false;
|
||||||
|
|
||||||
RoomlistModel *rooms = nullptr;
|
RoomlistModel *rooms_ = nullptr;
|
||||||
|
|
||||||
QHash<QString, QColor> userColors;
|
QHash<QString, QColor> userColors;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ void
|
||||||
NhekoDropArea::dropEvent(QDropEvent *event)
|
NhekoDropArea::dropEvent(QDropEvent *event)
|
||||||
{
|
{
|
||||||
if (event) {
|
if (event) {
|
||||||
auto model = ChatPage::instance()->timelineManager()->getHistoryView(roomid_);
|
auto model = ChatPage::instance()->timelineManager()->rooms()->getRoomById(roomid_);
|
||||||
if (model) {
|
if (model) {
|
||||||
model->input()->insertMimeData(event->mimeData());
|
model->input()->insertMimeData(event->mimeData());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue