Message menu rework
Rework the file menu so that it no longer relies on having a reference to the media delegate to manage a download for either opening externally or copying to clipboard. This allows the menus to be moved out of the delegates and maximize components and have them accessed through RoomManager. This reduces duplication and reduces the number of components in an already heavy delegate.
This commit is contained in:
@@ -25,6 +25,8 @@ Components.AlbumMaximizeComponent {
|
||||
|
||||
readonly property var currentTime: model.data(model.index(content.currentIndex, 0), MessageEventModel.TimeRole)
|
||||
|
||||
readonly property var currentDelegateType: model.data(model.index(content.currentIndex, 0), MessageEventModel.DelegateTypeRole)
|
||||
|
||||
readonly property string currentPlainText: model.data(model.index(content.currentIndex, 0), MessageEventModel.PlainText)
|
||||
|
||||
readonly property var currentMimeType: model.data(model.index(content.currentIndex, 0), MessageEventModel.MimeTypeRole)
|
||||
@@ -84,28 +86,26 @@ Components.AlbumMaximizeComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
onItemRightClicked: {
|
||||
const contextMenu = fileDelegateContextMenu.createObject(parent, {
|
||||
author: root.currentAuthor,
|
||||
eventId: root.currentEventId,
|
||||
file: parent,
|
||||
mimeType: root.currentMimeType,
|
||||
progressInfo: root.currentProgressInfo,
|
||||
plainText: root.currentPlainText,
|
||||
connection: root.currentRoom.connection
|
||||
});
|
||||
contextMenu.closeFullscreen.connect(root.close)
|
||||
contextMenu.open();
|
||||
}
|
||||
onItemRightClicked: RoomManager.viewEventMenu(root.currentEventId,
|
||||
root.currentAuthor,
|
||||
root.currentDelegateType,
|
||||
root.currentPlainText,
|
||||
"",
|
||||
"",
|
||||
root.currentMimeType,
|
||||
root.currentProgressInfo)
|
||||
|
||||
onSaveItem: {
|
||||
var dialog = saveAsDialog.createObject(QQC2.ApplicationWindow.overlay)
|
||||
dialog.open()
|
||||
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(root.currentEventId)
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileDelegateContextMenu
|
||||
FileDelegateContextMenu {}
|
||||
Connections {
|
||||
target: RoomManager
|
||||
function onCloseFullScreen() {
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
|
||||
@@ -36,7 +36,7 @@ TimelineContainer {
|
||||
readonly property bool downloaded: root.progressInfo && root.progressInfo.completed
|
||||
onDownloadedChanged: audio.play()
|
||||
|
||||
onOpenContextMenu: openFileContext(root)
|
||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||
|
||||
innerObject: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -43,7 +43,7 @@ TimelineContainer {
|
||||
openSavedFile();
|
||||
}
|
||||
|
||||
onOpenContextMenu: openFileContext(root)
|
||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||
|
||||
function saveFileAs() {
|
||||
const dialog = fileDialog.createObject(QQC2.ApplicationWindow.overlay)
|
||||
|
||||
@@ -53,7 +53,7 @@ TimelineContainer {
|
||||
*/
|
||||
readonly property var maxHeight: Kirigami.Units.gridUnit * 30
|
||||
|
||||
onOpenContextMenu: openFileContext(root)
|
||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||
|
||||
innerObject: Item {
|
||||
id: imageContainer
|
||||
|
||||
@@ -36,7 +36,7 @@ TimelineContainer {
|
||||
*/
|
||||
required property bool showLinkPreview
|
||||
|
||||
onOpenContextMenu: openMessageContext(label.selectedText)
|
||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, display, label.selectedText)
|
||||
|
||||
innerObject: ColumnLayout {
|
||||
Layout.maximumWidth: root.contentMaxWidth
|
||||
|
||||
@@ -589,44 +589,6 @@ ColumnLayout {
|
||||
return (yoff + height > 0 && yoff < ListView.view.height)
|
||||
}
|
||||
|
||||
Component {
|
||||
id: messageDelegateContextMenu
|
||||
MessageDelegateContextMenu {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileDelegateContextMenu
|
||||
FileDelegateContextMenu {}
|
||||
}
|
||||
|
||||
/// Open message context dialog for file and videos
|
||||
function openFileContext(file) {
|
||||
const contextMenu = fileDelegateContextMenu.createObject(root, {
|
||||
author: root.author,
|
||||
eventId: root.eventId,
|
||||
file: file,
|
||||
progressInfo: root.progressInfo,
|
||||
plainText: root.plainText,
|
||||
htmlText: root.display,
|
||||
connection: root.connection,
|
||||
});
|
||||
contextMenu.open();
|
||||
}
|
||||
|
||||
/// Open context menu for normal message
|
||||
function openMessageContext(selectedText) {
|
||||
const contextMenu = messageDelegateContextMenu.createObject(root, {
|
||||
selectedText: selectedText,
|
||||
author: root.author,
|
||||
eventId: root.eventId,
|
||||
eventType: root.delegateType,
|
||||
plainText: root.plainText,
|
||||
htmlText: root.display,
|
||||
connection: root.connection,
|
||||
});
|
||||
contextMenu.open();
|
||||
}
|
||||
|
||||
function setHoverActionsToDelegate() {
|
||||
if (ListView.view.setHoverActionsToDelegate) {
|
||||
ListView.view.setHoverActionsToDelegate(root)
|
||||
|
||||
@@ -54,7 +54,7 @@ TimelineContainer {
|
||||
*/
|
||||
readonly property var maxHeight: Kirigami.Units.gridUnit * 30
|
||||
|
||||
onOpenContextMenu: openFileContext(vid)
|
||||
onOpenContextMenu: RoomManager.viewEventMenu(eventId, author, delegateType, plainText, "", "", mediaInfo.mimeType, progressInfo)
|
||||
|
||||
onDownloadedChanged: {
|
||||
if (downloaded) {
|
||||
|
||||
@@ -9,36 +9,40 @@ import org.kde.kirigami 2.15 as Kirigami
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
/**
|
||||
* @brief The menu for media messages.
|
||||
*
|
||||
* This component just overloads the actions and nested actions of the base menu
|
||||
* to what is required for a media item.
|
||||
*
|
||||
* @sa MessageDelegateContextMenu
|
||||
*/
|
||||
MessageDelegateContextMenu {
|
||||
id: root
|
||||
|
||||
signal closeFullscreen
|
||||
|
||||
/**
|
||||
* @brief The MIME type of the media.
|
||||
*/
|
||||
property string mimeType
|
||||
|
||||
required property var file
|
||||
/**
|
||||
* @brief Progress info when downloading files.
|
||||
*
|
||||
* @sa Quotient::FileTransferInfo
|
||||
*/
|
||||
required property var progressInfo
|
||||
|
||||
/**
|
||||
* @brief The main list of menu item actions.
|
||||
*
|
||||
* Each action will be instantiated as a single line in the menu.
|
||||
*/
|
||||
property list<Kirigami.Action> actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Open Externally")
|
||||
icon.name: "document-open"
|
||||
onTriggered: {
|
||||
if (file.downloaded) {
|
||||
if (!UrlHelper.openUrl(progressInfo.localPath)) {
|
||||
UrlHelper.openUrl(progressInfo.localDir);
|
||||
}
|
||||
} else {
|
||||
file.onDownloadedChanged.connect(function() {
|
||||
if (!UrlHelper.openUrl(progressInfo.localPath)) {
|
||||
UrlHelper.openUrl(progressInfo.localDir);
|
||||
}
|
||||
});
|
||||
currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(eventId))
|
||||
}
|
||||
currentRoom.openEventMediaExternally(root.eventId)
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
@@ -56,21 +60,14 @@ MessageDelegateContextMenu {
|
||||
onTriggered: {
|
||||
currentRoom.chatBoxReplyId = eventId
|
||||
currentRoom.chatBoxEditId = ""
|
||||
root.closeFullscreen()
|
||||
RoomManager.requestFullScreenClose()
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Copy")
|
||||
icon.name: "edit-copy"
|
||||
onTriggered: {
|
||||
if(file.downloaded) {
|
||||
Clipboard.setImage(progressInfo.localPath)
|
||||
} else {
|
||||
file.onDownloadedChanged.connect(function() {
|
||||
Clipboard.setImage(progressInfo.localPath)
|
||||
});
|
||||
currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(eventId))
|
||||
}
|
||||
currentRoom.copyEventMedia(root.eventId)
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
@@ -99,12 +96,17 @@ MessageDelegateContextMenu {
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* @brief The list of menu item actions that have sub-actions.
|
||||
*
|
||||
* Each action will be instantiated as a single line that opens a sub menu.
|
||||
*/
|
||||
property list<Kirigami.Action> nestedActions: [
|
||||
ShareAction {
|
||||
id: shareAction
|
||||
inputData: {
|
||||
'urls': [],
|
||||
'mimeType': [root.mimeType ? root.mimeType : root.file.mediaINfo.mimeType]
|
||||
'mimeType': [root.mimeType]
|
||||
}
|
||||
property string filename: StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(eventId);
|
||||
|
||||
@@ -114,11 +116,12 @@ MessageDelegateContextMenu {
|
||||
Component.onCompleted: {
|
||||
shareAction.inputData = {
|
||||
urls: [filename],
|
||||
mimeType: [root.mimeType ? root.mimeType : root.file.mediaINfo.mimeType]
|
||||
mimeType: [root.mimeType]
|
||||
};
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Component {
|
||||
id: saveAsDialog
|
||||
FileDialog {
|
||||
|
||||
@@ -10,20 +10,82 @@ import org.kde.kirigamiaddons.labs.components 1.0 as KirigamiComponents
|
||||
|
||||
import org.kde.neochat 1.0
|
||||
|
||||
/**
|
||||
* @brief The base menu for most message types.
|
||||
*
|
||||
* This menu supports showing a list of actions to be shown for a particular event
|
||||
* delegate in a message timeline. The menu supports both desktop and mobile menus
|
||||
* with different visuals appropriate to the platform.
|
||||
*
|
||||
* The menu supports both a list of main actions and the ability to define sub menus
|
||||
* using the nested action parameter.
|
||||
*
|
||||
* For event types that need alternate actions this class can be used as a base and
|
||||
* the actions and nested actions can be overwritten to show the alternate items.
|
||||
*/
|
||||
Loader {
|
||||
id: root
|
||||
|
||||
required property var author
|
||||
required property string eventId
|
||||
property var eventType
|
||||
property string selectedText: ""
|
||||
required property string plainText
|
||||
property string htmlText: undefined
|
||||
|
||||
/**
|
||||
* @brief The curent connection for the account accessing the event.
|
||||
*/
|
||||
required property NeoChatConnection connection
|
||||
|
||||
/**
|
||||
* @brief The matrix ID of the message event.
|
||||
*/
|
||||
required property string eventId
|
||||
|
||||
/**
|
||||
* @brief The message author.
|
||||
*
|
||||
* This should consist of the following:
|
||||
* - id - The matrix ID of the author.
|
||||
* - isLocalUser - Whether the author is the local user.
|
||||
* - avatarSource - The mxc URL for the author's avatar in the current room.
|
||||
* - avatarMediaId - The media ID of the author's avatar.
|
||||
* - avatarUrl - The mxc URL for the author's avatar.
|
||||
* - displayName - The display name of the author.
|
||||
* - display - The name of the author.
|
||||
* - color - The color for the author.
|
||||
* - object - The Quotient::User object for the author.
|
||||
*
|
||||
* @sa Quotient::User
|
||||
*/
|
||||
required property var author
|
||||
|
||||
/**
|
||||
* @brief The delegate type of the message.
|
||||
*/
|
||||
required property int delegateType
|
||||
|
||||
/**
|
||||
* @brief The display text of the message as plain text.
|
||||
*/
|
||||
required property string plainText
|
||||
|
||||
/**
|
||||
* @brief The display text of the message as rich text.
|
||||
*/
|
||||
property string htmlText: ""
|
||||
|
||||
/**
|
||||
* @brief The text the user currently has selected.
|
||||
*/
|
||||
property string selectedText: ""
|
||||
|
||||
/**
|
||||
* @brief The list of menu item actions that have sub-actions.
|
||||
*
|
||||
* Each action will be instantiated as a single line that open a sub menu.
|
||||
*/
|
||||
property list<Kirigami.Action> nestedActions
|
||||
|
||||
/**
|
||||
* @brief The main list of menu item actions.
|
||||
*
|
||||
* Each action will be instantiated as a single line in the menu.
|
||||
*/
|
||||
property list<Kirigami.Action> actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Edit")
|
||||
@@ -32,7 +94,7 @@ Loader {
|
||||
currentRoom.chatBoxEditId = eventId;
|
||||
currentRoom.chatBoxReplyId = "";
|
||||
}
|
||||
visible: author.id === root.connection.localUserId && (root.eventType === DelegateType.Emote || root.eventType === DelegateType.Message)
|
||||
visible: author.isLocalUser && (root.delegateType === DelegateType.Emote || root.delegateType === DelegateType.Message)
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Reply")
|
||||
@@ -53,13 +115,13 @@ Loader {
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
})
|
||||
page.chosen.connect(function(targetRoomId) {
|
||||
root.connection.room(targetRoomId).postHtmlMessage(root.plainText, root.htmlText ? root.htmlText : root.plainText)
|
||||
root.connection.room(targetRoomId).postHtmlMessage(root.plainText, root.htmlText.length > 0 ? root.htmlText : root.plainText)
|
||||
page.closeDialog()
|
||||
})
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
visible: author.id === currentRoom.localUser.id || currentRoom.canSendState("redact")
|
||||
visible: author.isLocalUser || currentRoom.canSendState("redact")
|
||||
text: i18n("Remove")
|
||||
icon.name: "edit-delete-remove"
|
||||
icon.color: "red"
|
||||
@@ -71,12 +133,12 @@ Loader {
|
||||
Kirigami.Action {
|
||||
text: i18n("Copy")
|
||||
icon.name: "edit-copy"
|
||||
onTriggered: Clipboard.saveText(root.selectedText === "" ? root.plainText : root.selectedText)
|
||||
onTriggered: Clipboard.saveText(root.selectedText.length > 0 ? root.plainText : root.selectedText)
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18nc("@action:button 'Report' as in 'Report this event to the administrators'", "Report")
|
||||
icon.name: "dialog-warning-symbolic"
|
||||
visible: author.id !== currentRoom.localUser.id
|
||||
visible: author.isLocalUser
|
||||
onTriggered: applicationWindow().pageStack.pushDialogLayer("qrc:/ReportSheet.qml", {room: currentRoom, eventId: eventId}, {
|
||||
title: i18nc("@title", "Report Message"),
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
@@ -116,12 +178,10 @@ Loader {
|
||||
icon.name: modelData.icon.name
|
||||
onTriggered: modelData.trigger()
|
||||
}
|
||||
onObjectAdded: {
|
||||
menuItem.insertItem(0, object)
|
||||
}
|
||||
onObjectAdded: (index, object) => {menuItem.insertItem(0, object)}
|
||||
}
|
||||
}
|
||||
onObjectAdded: {
|
||||
onObjectAdded: (index, object) => {
|
||||
object.visible = false;
|
||||
menu.addMenu(object)
|
||||
}
|
||||
@@ -130,7 +190,6 @@ Loader {
|
||||
Repeater {
|
||||
model: root.actions
|
||||
QQC2.MenuItem {
|
||||
id: menuItem
|
||||
visible: modelData.visible
|
||||
action: modelData
|
||||
onClicked: root.item.close();
|
||||
@@ -147,7 +206,7 @@ Loader {
|
||||
Instantiator {
|
||||
model: WebShortcutModel {
|
||||
id: webshortcutmodel
|
||||
selectedText: root.selectedText ? root.selectedText : root.plainText
|
||||
selectedText: root.selectedText.length > 0 ? root.selectedText : root.plainText
|
||||
onOpenUrl: RoomManager.visitNonMatrix(url)
|
||||
}
|
||||
delegate: QQC2.MenuItem {
|
||||
|
||||
@@ -208,6 +208,30 @@ Kirigami.Page {
|
||||
width: Kirigami.Units.gridUnit * 25
|
||||
});
|
||||
}
|
||||
|
||||
function onShowMessageMenu(eventId, author, delegateType, plainText, htmlText, selectedText) {
|
||||
const contextMenu = messageDelegateContextMenu.createObject(root, {
|
||||
selectedText: selectedText,
|
||||
author: author,
|
||||
eventId: eventId,
|
||||
delegateType: delegateType,
|
||||
plainText: plainText,
|
||||
htmlText: htmlText
|
||||
});
|
||||
contextMenu.open();
|
||||
}
|
||||
|
||||
function onShowFileMenu(eventId, author, delegateType, plainText, mimeType, progressInfo) {
|
||||
const contextMenu = fileDelegateContextMenu.createObject(root, {
|
||||
author: author,
|
||||
eventId: eventId,
|
||||
delegateType: delegateType,
|
||||
plainText: plainText,
|
||||
mimeType: mimeType,
|
||||
progressInfo: progressInfo
|
||||
});
|
||||
contextMenu.open();
|
||||
}
|
||||
}
|
||||
|
||||
function showUserDetail(user) {
|
||||
@@ -221,4 +245,18 @@ Kirigami.Page {
|
||||
id: userDetailDialog
|
||||
UserDetailDialog {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: messageDelegateContextMenu
|
||||
MessageDelegateContextMenu {
|
||||
connection: root.connection
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: fileDelegateContextMenu
|
||||
FileDelegateContextMenu {
|
||||
connection: root.connection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user