diff --git a/src/qml/DelegateContextMenu.qml b/src/qml/DelegateContextMenu.qml index fb5f6930f..956ed9269 100644 --- a/src/qml/DelegateContextMenu.qml +++ b/src/qml/DelegateContextMenu.qml @@ -9,6 +9,7 @@ import Qt.labs.qmlmodels import org.kde.kirigami as Kirigami import org.kde.kirigamiaddons.components as KirigamiComponents import org.kde.kirigamiaddons.formcard as FormCard +import org.kde.kirigamiaddons.delegates as Delegates import org.kde.neochat @@ -25,7 +26,7 @@ import org.kde.neochat * 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 { +KirigamiComponents.ConvergentContextMenu { id: root /** @@ -62,25 +63,6 @@ Loader { */ property string hoveredLink: "" - /** - * @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 nestedActions - - /** - * @brief The main list of menu item actions. - * - * Each action will be instantiated as a single line in the menu. - */ - property list actions - - /** - * @brief Whether the web search menu should be shown or not. - */ - property bool enableWebSearch: true - /** * Some common actions shared between menus */ @@ -112,7 +94,7 @@ Loader { } } - component ReplyMessageAction: Kirigami.Action { + component ReplyMessageAction: QQC2.Action { text: i18n("Reply") icon.name: "mail-replied-symbolic" onTriggered: { @@ -150,90 +132,70 @@ Loader { } } - Component { - id: regularMenu + headerContentItem: RowLayout { + spacing: Kirigami.Units.largeSpacing - QQC2.Menu { - id: menu - Instantiator { - model: root.nestedActions - delegate: QQC2.Menu { - id: menuItem - visible: modelData.visible - title: modelData.text - icon: modelData.icon + KirigamiComponents.Avatar { + source: root.author.avatarUrl - Instantiator { - model: modelData.children - delegate: QQC2.MenuItem { - text: modelData.text - icon.name: modelData.icon.name - onTriggered: modelData.trigger() - } - onObjectAdded: (index, object) => { - menuItem.insertItem(0, object); - } - } - } - onObjectAdded: (index, object) => { - object.visible = false; - menu.addMenu(object); - } + Layout.preferredWidth: Kirigami.Units.gridUnit * 2 + Layout.preferredHeight: Kirigami.Units.gridUnit * 2 + Layout.alignment: Qt.AlignTop + } + + ColumnLayout { + spacing: 0 + + Layout.fillWidth: true + + Kirigami.Heading { + level: 4 + text: root.author.htmlSafeDisplayName + wrapMode: Text.WordWrap + Layout.fillWidth: true } + QQC2.Label { + text: root.plainText + textFormat: Text.PlainText + elide: Text.ElideRight + onLinkActivated: RoomManager.resolveResource(link, "join") + Layout.fillWidth: true + } + } + } + + Kirigami.Action { + visible: Kirigami.Settings.isMobile + + displayComponent: RowLayout { + spacing: 0 + Layout.fillWidth: true + Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5 Repeater { - model: root.actions - DelegateChooser { - role: "separator" - DelegateChoice { - roleValue: true + model: ["๐Ÿ‘", "๐Ÿ‘Ž๏ธ", "๐Ÿ˜„", "๐ŸŽ‰", "๐Ÿš€", "๐Ÿ‘€"] + delegate: Delegates.RoundedItemDelegate { + Layout.fillWidth: true + Layout.fillHeight: true - QQC2.MenuSeparator { - visible: modelData.visible - } + contentItem: Kirigami.Heading { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font.family: "emoji" + text: modelData } - DelegateChoice { - roleValue: false - - QQC2.MenuItem { - visible: modelData.visible - action: modelData - onClicked: root.item.close() - } + onClicked: { + currentRoom.toggleReaction(eventId, modelData); + root.item.close(); } } } - QQC2.Menu { - id: webshortcutmenu - title: i18n("Search for '%1'", webshortcutmodel.trunkatedSearchText) - icon.name: "search-symbolic" - property bool isVisible: webshortcutmodel.enabled && root.enableWebSearch - Component.onCompleted: { - webshortcutmenu.parent.visible = isVisible; - } - onIsVisibleChanged: webshortcutmenu.parent.visible = isVisible - Instantiator { - model: WebShortcutModel { - id: webshortcutmodel - selectedText: root.selectedText.length > 0 ? root.selectedText : root.plainText - onOpenUrl: url => RoomManager.resolveResource(url.toString()) - } - delegate: QQC2.MenuItem { - text: model.display - icon.name: model.decoration - onTriggered: webshortcutmodel.trigger(model.edit) - } - onObjectAdded: (index, object) => webshortcutmenu.insertItem(0, object) - } - QQC2.MenuSeparator {} - QQC2.MenuItem { - text: i18n("Configure Web Shortcuts...") - icon.name: "configure" - visible: !Controller.isFlatpak - onTriggered: webshortcutmodel.configureWebShortcuts() - } - } + } + } + + /* } } Component { @@ -330,31 +292,6 @@ Loader { Kirigami.Separator { Layout.fillWidth: true } - RowLayout { - spacing: 0 - Layout.fillWidth: true - Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5 - Repeater { - model: ["๐Ÿ‘", "๐Ÿ‘Ž๏ธ", "๐Ÿ˜„", "๐ŸŽ‰", "๐Ÿš€", "๐Ÿ‘€"] - delegate: QQC2.ItemDelegate { - Layout.fillWidth: true - Layout.fillHeight: true - - contentItem: Kirigami.Heading { - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - font.family: "emoji" - text: modelData - } - - onClicked: { - currentRoom.toggleReaction(eventId, modelData); - root.item.close(); - } - } - } - } Kirigami.Separator { Layout.fillWidth: true } @@ -422,5 +359,5 @@ Loader { } else { item.popup(); } - } + }*/ } diff --git a/src/qml/FileDelegateContextMenu.qml b/src/qml/FileDelegateContextMenu.qml index 8cc1e5711..418eb3adf 100644 --- a/src/qml/FileDelegateContextMenu.qml +++ b/src/qml/FileDelegateContextMenu.qml @@ -33,107 +33,97 @@ DelegateContextMenu { */ required property var progressInfo - // Web search isn't useful for images - enableWebSearch: false + DelegateContextMenu.ReplyMessageAction {} - /** - * @brief The main list of menu item actions. - * - * Each action will be instantiated as a single line in the menu. - */ - property list actions: [ - DelegateContextMenu.ReplyMessageAction {}, - Kirigami.Action { - separator: true - }, - Kirigami.Action { - text: i18nc("@action:inmenu", "Open Image") - icon.name: "document-open" - onTriggered: { - currentRoom.openEventMediaExternally(root.eventId); - } - }, - Kirigami.Action { - text: i18nc("@action:inmenu", "Save Imageโ€ฆ") - icon.name: "document-save" - onTriggered: { - var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay); - dialog.selectedFile = currentRoom.fileNameToDownload(eventId); - dialog.open(); - } - }, - Kirigami.Action { - text: i18nc("@action:inmenu", "Copy Image") - icon.name: "edit-copy" - onTriggered: { - currentRoom.copyEventMedia(root.eventId); - } - }, - Kirigami.Action { - separator: true - }, - Kirigami.Action { - visible: author.id === currentRoom.localMember.id || currentRoom.canSendState("redact") - text: i18n("Remove") - icon.name: "edit-delete-remove" - icon.color: "red" - onTriggered: { - let dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), { - title: i18nc("@title:dialog", "Remove Message"), - placeholder: i18nc("@info:placeholder", "Reason for removing this message"), - actionText: i18nc("@action:button 'Remove' as in 'Remove this message'", "Remove"), - icon: "delete" - }, { - title: i18nc("@title:dialog", "Remove Message"), - width: Kirigami.Units.gridUnit * 25 - }); - dialog.accepted.connect(reason => { - currentRoom.redactEvent(root.eventId, reason); - }); - } - }, - DelegateContextMenu.ReportMessageAction {}, - DelegateContextMenu.ShowUserAction {}, - Kirigami.Action { - separator: true - visible: viewSourceAction.visible - }, - DelegateContextMenu.ViewSourceAction { - id: viewSourceAction + Kirigami.Action { + separator: true + } + + QQC2.Action { + text: i18nc("@action:inmenu", "Open Image") + icon.name: "document-open" + onTriggered: { + currentRoom.openEventMediaExternally(root.eventId); } - ] + } - /** - * @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 nestedActions: [ - ShareAction { - id: shareAction - inputData: { - "urls": [filename], - "mimeType": [root.mimeType] - } - room: currentRoom - eventId: root.eventId - property string filename: Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(eventId) + QQC2.Action { + text: i18nc("@action:inmenu", "Save Imageโ€ฆ") + icon.name: "document-save" + onTriggered: { + var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay); + dialog.selectedFile = currentRoom.fileNameToDownload(eventId); + dialog.open(); } - ] + } - Component { - id: saveAsDialog - Dialogs.FileDialog { - fileMode: Dialogs.FileDialog.SaveFile - currentFolder: NeoChatConfig.lastSaveDirectory.length > 0 ? NeoChatConfig.lastSaveDirectory : Core.StandardPaths.writableLocation(Core.StandardPaths.DownloadLocation) - onAccepted: { - if (!selectedFile) { - return; - } - NeoChatConfig.lastSaveDirectory = currentFolder; - NeoChatConfig.save(); - currentRoom.downloadFile(eventId, selectedFile); + QQC2.Action { + text: i18nc("@action:inmenu", "Copy Image") + icon.name: "edit-copy" + onTriggered: { + currentRoom.copyEventMedia(root.eventId); + } + } + + Kirigami.Action { + separator: true + } + + Kirigami.Action { + visible: author.id === currentRoom.localMember.id || currentRoom.canSendState("redact") + text: i18n("Remove") + icon.name: "edit-delete-remove" + icon.color: "red" + onTriggered: { + let dialog = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), { + title: i18nc("@title:dialog", "Remove Message"), + placeholder: i18nc("@info:placeholder", "Reason for removing this message"), + actionText: i18nc("@action:button 'Remove' as in 'Remove this message'", "Remove"), + icon: "delete" + }, { + title: i18nc("@title:dialog", "Remove Message"), + width: Kirigami.Units.gridUnit * 25 + }); + dialog.accepted.connect(reason => { + currentRoom.redactEvent(root.eventId, reason); + }); + } + } + + DelegateContextMenu.ReportMessageAction {} + + DelegateContextMenu.ShowUserAction {} + + Kirigami.Action { + separator: true + visible: viewSourceAction.visible + } + + DelegateContextMenu.ViewSourceAction { + id: viewSourceAction + } + + ShareAction { + id: shareAction + inputData: { + "urls": [filename], + "mimeType": [root.mimeType] + } + room: currentRoom + eventId: root.eventId + property string filename: Core.StandardPaths.writableLocation(Core.StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_").replace("/", "_").replace("+", "_") + currentRoom.fileNameToDownload(eventId) + } + + readonly property Component saveAsDialog: Dialogs.FileDialog { + fileMode: Dialogs.FileDialog.SaveFile + currentFolder: NeoChatConfig.lastSaveDirectory.length > 0 ? NeoChatConfig.lastSaveDirectory : Core.StandardPaths.writableLocation(Core.StandardPaths.DownloadLocation) + onAccepted: { + if (!selectedFile) { + return; } + NeoChatConfig.lastSaveDirectory = currentFolder; + NeoChatConfig.save(); + currentRoom.downloadFile(eventId, selectedFile); } } } diff --git a/src/qml/MessageDelegateContextMenu.qml b/src/qml/MessageDelegateContextMenu.qml index 42695e8af..a92bf6f78 100644 --- a/src/qml/MessageDelegateContextMenu.qml +++ b/src/qml/MessageDelegateContextMenu.qml @@ -32,67 +32,101 @@ DelegateContextMenu { */ required property string htmlText - actions: [ - Kirigami.Action { - text: i18n("Edit") - icon.name: "document-edit" - onTriggered: { - currentRoom.editCache.editId = eventId; - currentRoom.mainCache.replyId = ""; - currentRoom.mainCache.threadId = ""; - } - visible: root.author.isLocalMember && root.messageComponentType === MessageComponentType.Text - }, - DelegateContextMenu.ReplyMessageAction {}, - Kirigami.Action { - text: i18nc("@action:inmenu As in 'Forward this message'", "Forwardโ€ฆ") - icon.name: "mail-forward-symbolic" - onTriggered: { - let page = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), { - connection: root.connection - }, { - title: i18nc("@title", "Forward Message"), - width: Kirigami.Units.gridUnit * 25 - }); - page.chosen.connect(function (targetRoomId) { - root.connection.room(targetRoomId).postHtmlMessage(root.plainText, root.htmlText.length > 0 ? root.htmlText : root.plainText); - page.closeDialog(); - }); - } - }, - Kirigami.Action { - separator: true - }, - DelegateContextMenu.RemoveMessageAction {}, - Kirigami.Action { - text: i18nc("@action:inmenu", "Copy Link Address") - icon.name: "edit-copy" - visible: root.hoveredLink.length > 0 - onTriggered: Clipboard.saveText(root.hoveredLink) - }, - Kirigami.Action { - text: i18nc("@action:inmenu", "Copy Text") - icon.name: "edit-copy" - onTriggered: Clipboard.saveText(root.selectedText.length > 0 ? root.selectedText : root.plainText) - }, - Kirigami.Action { - text: i18nc("@action:inmenu", "Copy Message Link") - icon.name: "edit-copy" - onTriggered: { - Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId); - } - }, - Kirigami.Action { - separator: true - }, - DelegateContextMenu.ReportMessageAction {}, - DelegateContextMenu.ShowUserAction {}, - Kirigami.Action { - separator: true - visible: viewSourceAction.visible - }, - DelegateContextMenu.ViewSourceAction { - id: viewSourceAction + Kirigami.Action { + text: i18n("Edit") + icon.name: "document-edit" + onTriggered: { + currentRoom.editCache.editId = eventId; + currentRoom.mainCache.replyId = ""; + currentRoom.mainCache.threadId = ""; } - ] + visible: root.author.isLocalMember && root.messageComponentType === MessageComponentType.Text + } + + DelegateContextMenu.ReplyMessageAction {} + + QQC2.Action { + text: i18nc("@action:inmenu As in 'Forward this message'", "Forwardโ€ฆ") + icon.name: "mail-forward-symbolic" + onTriggered: { + let page = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), { + connection: root.connection + }, { + title: i18nc("@title", "Forward Message"), + width: Kirigami.Units.gridUnit * 25 + }); + page.chosen.connect(function (targetRoomId) { + root.connection.room(targetRoomId).postHtmlMessage(root.plainText, root.htmlText.length > 0 ? root.htmlText : root.plainText); + page.closeDialog(); + }); + } + } + Kirigami.Action { + separator: true + } + DelegateContextMenu.RemoveMessageAction {} + Kirigami.Action { + text: i18nc("@action:inmenu", "Copy Link Address") + icon.name: "edit-copy" + visible: root.hoveredLink.length > 0 + onTriggered: Clipboard.saveText(root.hoveredLink) + } + QQC2.Action { + text: i18nc("@action:inmenu", "Copy Text") + icon.name: "edit-copy" + onTriggered: Clipboard.saveText(root.selectedText.length > 0 ? root.selectedText : root.plainText) + } + QQC2.Action { + text: i18nc("@action:inmenu", "Copy Message Link") + icon.name: "edit-copy" + onTriggered: { + Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId); + } + } + Kirigami.Action { + separator: true + } + DelegateContextMenu.ReportMessageAction {} + DelegateContextMenu.ShowUserAction {} + Kirigami.Action { + separator: true + visible: viewSourceAction.visible + } + DelegateContextMenu.ViewSourceAction { + id: viewSourceAction + } + + Kirigami.Action { + separator: true + visible: webShortcutModel.enabled + } + + Kirigami.Action { + id: webShortcutModelAction + + text: i18n("Search for '%1'", webshortcutModel.trunkatedSearchText) + icon.name: "search-symbolic" + visible: webshortcutModel.enabled + + readonly property Instantiator instantiator: Instantiator { + model: WebShortcutModel { + id: webshortcutModel + selectedText: root.selectedText.length > 0 ? root.selectedText : root.plainText + onOpenUrl: url => RoomManager.resolveResource(url.toString()) + } + delegate: QQC2.Action { + text: model.display + icon.name: model.decoration + onTriggered: webshortcutModel.trigger(model.edit) + } + onObjectAdded: (index, object) => webShortcutModelAction.children.push(object) + } + } + + Kirigami.Action { + text: i18n("Configure Web Shortcuts...") + icon.name: "configure" + visible: !Controller.isFlatpak && webshortcutModel.enabled + onTriggered: webshortcutmodel.configureWebShortcuts() + } } diff --git a/src/qml/RoomPage.qml b/src/qml/RoomPage.qml index dd4e2f1c1..5279bf59d 100644 --- a/src/qml/RoomPage.qml +++ b/src/qml/RoomPage.qml @@ -255,7 +255,7 @@ Kirigami.Page { plainText: plainText, htmlText: htmlText, }); - contextMenu.open(); + contextMenu.popup(); } function onShowFileMenu(eventId, author, messageComponentType, plainText, mimeType, progressInfo, isThread) { @@ -266,7 +266,7 @@ Kirigami.Page { mimeType: mimeType, progressInfo: progressInfo, }); - contextMenu.open(); + contextMenu.popup(); } function onShowMaximizedMedia(index) {