Unify Delegate context menus
The menus have always been split into a menu for file-like content and text-like content This split makes some things a bit more complicated then necessary.
This commit is contained in:
@@ -215,21 +215,8 @@ Kirigami.Page {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onShowMessageMenu(eventId, author, messageComponentType, plainText, htmlText, selectedText, hoveredLink, isThread) {
|
function onShowDelegateMenu(eventId: string, author, messageComponentType, plainText: string, richText: string, mimeType: string, progressInfo, isThread: bool, selectedText: string, hoveredLink: string) {
|
||||||
const contextMenu = messageDelegateContextMenu.createObject(root, {
|
const contextMenu = delegateContextMenu.createObject(root, {
|
||||||
selectedText: selectedText,
|
|
||||||
hoveredLink: hoveredLink,
|
|
||||||
author: author,
|
|
||||||
eventId: eventId,
|
|
||||||
messageComponentType: messageComponentType,
|
|
||||||
plainText: plainText,
|
|
||||||
htmlText: htmlText,
|
|
||||||
});
|
|
||||||
contextMenu.popup();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onShowFileMenu(eventId, author, messageComponentType, plainText, mimeType, progressInfo, isThread) {
|
|
||||||
const contextMenu = fileDelegateContextMenu.createObject(root, {
|
|
||||||
author: author,
|
author: author,
|
||||||
eventId: eventId,
|
eventId: eventId,
|
||||||
plainText: plainText,
|
plainText: plainText,
|
||||||
@@ -262,16 +249,8 @@ Kirigami.Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: messageDelegateContextMenu
|
id: delegateContextMenu
|
||||||
MessageDelegateContextMenu {
|
DelegateContextMenu {
|
||||||
room: root.currentRoom
|
|
||||||
connection: root.currentRoom.connection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: fileDelegateContextMenu
|
|
||||||
FileDelegateContextMenu {
|
|
||||||
room: root.currentRoom
|
room: root.currentRoom
|
||||||
connection: root.currentRoom.connection
|
connection: root.currentRoom.connection
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,23 +279,15 @@ void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, Neoch
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &event = **it;
|
const auto &event = **it;
|
||||||
if (EventHandler::mediaInfo(room, &event).contains("mimeType"_L1)) {
|
Q_EMIT showDelegateMenu(eventId,
|
||||||
Q_EMIT showFileMenu(eventId,
|
|
||||||
sender,
|
sender,
|
||||||
MessageComponentType::typeForEvent(event),
|
MessageComponentType::typeForEvent(event),
|
||||||
EventHandler::plainBody(room, &event),
|
EventHandler::plainBody(room, &event),
|
||||||
|
EventHandler::richBody(room, &event),
|
||||||
EventHandler::mediaInfo(room, &event)["mimeType"_L1].toString(),
|
EventHandler::mediaInfo(room, &event)["mimeType"_L1].toString(),
|
||||||
room->fileTransferInfo(eventId));
|
room->fileTransferInfo(eventId),
|
||||||
return;
|
selectedText,
|
||||||
}
|
hoveredLink);
|
||||||
|
|
||||||
Q_EMIT showMessageMenu(eventId,
|
|
||||||
sender,
|
|
||||||
MessageComponentType::typeForEvent(event),
|
|
||||||
EventHandler::plainBody(room, &event),
|
|
||||||
EventHandler::richBody(room, &event),
|
|
||||||
selectedText,
|
|
||||||
hoveredLink);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RoomManager::hasOpenRoom() const
|
bool RoomManager::hasOpenRoom() const
|
||||||
|
|||||||
@@ -296,23 +296,15 @@ Q_SIGNALS:
|
|||||||
/**
|
/**
|
||||||
* @brief Request to show a menu for the given event.
|
* @brief Request to show a menu for the given event.
|
||||||
*/
|
*/
|
||||||
void showMessageMenu(const QString &eventId,
|
void showDelegateMenu(const QString &eventId,
|
||||||
const NeochatRoomMember *author,
|
const NeochatRoomMember *author,
|
||||||
MessageComponentType::Type messageComponentType,
|
MessageComponentType::Type messageComponentType,
|
||||||
const QString &plainText,
|
const QString &plainText,
|
||||||
const QString &htmlText,
|
const QString &richtText,
|
||||||
const QString &selectedText,
|
const QString &mimeType,
|
||||||
const QString &hoveredLink);
|
const FileTransferInfo &progressInfo,
|
||||||
|
const QString &selectedText,
|
||||||
/**
|
const QString &hoveredLink);
|
||||||
* @brief Request to show a menu for the given media event.
|
|
||||||
*/
|
|
||||||
void showFileMenu(const QString &eventId,
|
|
||||||
const NeochatRoomMember *author,
|
|
||||||
MessageComponentType::Type messageComponentType,
|
|
||||||
const QString &plainText,
|
|
||||||
const QString &mimeType,
|
|
||||||
const FileTransferInfo &progressInfo);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Show the direct chat confirmation dialog.
|
* @brief Show the direct chat confirmation dialog.
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ ecm_add_qml_module(Timeline GENERATE_PLUGIN_SOURCE
|
|||||||
QuickActions.qml
|
QuickActions.qml
|
||||||
TypingPane.qml
|
TypingPane.qml
|
||||||
DelegateContextMenu.qml
|
DelegateContextMenu.qml
|
||||||
FileDelegateContextMenu.qml
|
|
||||||
MessageDelegateContextMenu.qml
|
|
||||||
SOURCES
|
SOURCES
|
||||||
messageattached.cpp
|
messageattached.cpp
|
||||||
messagedelegate.cpp
|
messagedelegate.cpp
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
import QtCore as Core
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls as QQC2
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Dialogs as Dialogs
|
||||||
|
|
||||||
import Qt.labs.qmlmodels
|
import Qt.labs.qmlmodels
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
import org.kde.kirigamiaddons.components as KirigamiComponents
|
||||||
@@ -14,7 +17,7 @@ import org.kde.kirigamiaddons.delegates as Delegates
|
|||||||
import org.kde.neochat
|
import org.kde.neochat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The base menu for most message types.
|
* @brief The menu for most message types.
|
||||||
*
|
*
|
||||||
* This menu supports showing a list of actions to be shown for a particular event
|
* 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
|
* delegate in a message timeline. The menu supports both desktop and mobile menus
|
||||||
@@ -22,9 +25,6 @@ import org.kde.neochat
|
|||||||
*
|
*
|
||||||
* The menu supports both a list of main actions and the ability to define sub menus
|
* The menu supports both a list of main actions and the ability to define sub menus
|
||||||
* using the nested action parameter.
|
* 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.
|
|
||||||
*/
|
*/
|
||||||
KirigamiComponents.ConvergentContextMenu {
|
KirigamiComponents.ConvergentContextMenu {
|
||||||
id: root
|
id: root
|
||||||
@@ -74,122 +74,26 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
property string hoveredLink: ""
|
property string hoveredLink: ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some common actions shared between menus
|
* @brief The HTML text of the event, if it is has one.
|
||||||
*/
|
*/
|
||||||
component ViewSourceAction: Kirigami.Action {
|
property string htmlText: ""
|
||||||
visible: NeoChatConfig.developerTools
|
|
||||||
text: i18n("View Source")
|
|
||||||
icon.name: "code-context"
|
|
||||||
onTriggered: RoomManager.viewEventSource(root.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
component RemoveMessageAction: Kirigami.Action {
|
/**
|
||||||
visible: (author.isLocalMember || currentRoom.canSendState("redact")) && root.messageComponentType !== MessageComponentType.Other
|
* @brief Progress info when downloading files.
|
||||||
text: i18nc("@action:button", "Remove…")
|
*
|
||||||
icon.name: "edit-delete-remove"
|
* @sa Quotient::FileTransferInfo
|
||||||
icon.color: "red"
|
*/
|
||||||
onTriggered: {
|
required property var progressInfo
|
||||||
let dialog = (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component ReplyMessageAction: Kirigami.Action {
|
/**
|
||||||
visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent
|
* @brief The MIME type of the media, or an empty string if the event does not have file content
|
||||||
text: i18n("Reply")
|
*/
|
||||||
icon.name: "mail-replied-symbolic"
|
property string mimeType
|
||||||
onTriggered: {
|
|
||||||
currentRoom.mainCache.replyId = eventId;
|
|
||||||
currentRoom.editCache.editId = "";
|
|
||||||
RoomManager.requestFullScreenClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component ReplyThreadMessageAction: Kirigami.Action {
|
/**
|
||||||
visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent
|
* @brief Whether the event has file-based content. This includes images, videos, and other files
|
||||||
text: i18nc("@action:button", "Reply in Thread")
|
*/
|
||||||
icon.name: "dialog-messages"
|
readonly property bool hasFileContent: mimeType.length > 0
|
||||||
onTriggered: {
|
|
||||||
currentRoom.threadCache.replyId = "";
|
|
||||||
currentRoom.threadCache.threadId = currentRoom.eventIsThreaded(root.eventId) ? currentRoom.rootIdForThread(root.eventId) : root.eventId;
|
|
||||||
currentRoom.mainCache.clearRelations();
|
|
||||||
currentRoom.editCache.clearRelations();
|
|
||||||
RoomManager.requestFullScreenClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
component ReportMessageAction: Kirigami.Action {
|
|
||||||
text: i18nc("@action:button 'Report' as in 'Report this event to the administrators'", "Report…")
|
|
||||||
icon.name: "dialog-warning-symbolic"
|
|
||||||
visible: !author.isLocalMember
|
|
||||||
onTriggered: {
|
|
||||||
let dialog = (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
|
||||||
title: i18nc("@title:dialog", "Report Message"),
|
|
||||||
placeholder: i18nc("@info:placeholder", "Reason for reporting this message"),
|
|
||||||
icon: "dialog-warning-symbolic",
|
|
||||||
actionText: i18nc("@action:button 'Report' as in 'Report this event to the administrators'", "Report")
|
|
||||||
}, {
|
|
||||||
title: i18nc("@title", "Report Message"),
|
|
||||||
width: Kirigami.Units.gridUnit * 25
|
|
||||||
});
|
|
||||||
dialog.accepted.connect(reason => {
|
|
||||||
currentRoom.reportEvent(root.eventId, reason);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component PinMessageAction: Kirigami.Action {
|
|
||||||
readonly property bool pinned: currentRoom.isEventPinned(root.eventId)
|
|
||||||
|
|
||||||
visible: currentRoom.canSendState("m.room.pinned_events") && root.messageComponentType !== MessageComponentType.Other
|
|
||||||
text: pinned ? i18nc("@action:button 'Unpin' as in 'Unpin this message'", "Unpin") : i18nc("@action:button 'Pin' as in 'Pin the message in the room'", "Pin")
|
|
||||||
icon.name: pinned ? "window-unpin-symbolic" : "pin-symbolic"
|
|
||||||
onTriggered: pinned ? currentRoom.unpinEvent(root.eventId) : currentRoom.pinEvent(root.eventId)
|
|
||||||
}
|
|
||||||
|
|
||||||
headerContentItem: RowLayout {
|
|
||||||
spacing: Kirigami.Units.largeSpacing
|
|
||||||
|
|
||||||
KirigamiComponents.Avatar {
|
|
||||||
source: root.author.avatarUrl
|
|
||||||
|
|
||||||
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 {
|
Kirigami.Action {
|
||||||
id: emojiAction
|
id: emojiAction
|
||||||
@@ -247,167 +151,303 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
Kirigami.Action {
|
||||||
|
separator: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent
|
||||||
|
text: i18nc("@action:inmenu", "Reply")
|
||||||
|
icon.name: "mail-replied-symbolic"
|
||||||
|
onTriggered: {
|
||||||
|
currentRoom.mainCache.replyId = eventId;
|
||||||
|
currentRoom.editCache.editId = "";
|
||||||
|
RoomManager.requestFullScreenClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component {
|
|
||||||
id: mobileMenu
|
|
||||||
|
|
||||||
Kirigami.OverlayDrawer {
|
Kirigami.Action {
|
||||||
id: drawer
|
visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent
|
||||||
height: stackView.implicitHeight
|
text: i18nc("@action:inmenu", "Reply in Thread")
|
||||||
edge: Qt.BottomEdge
|
icon.name: "dialog-messages"
|
||||||
padding: 0
|
onTriggered: {
|
||||||
leftPadding: 0
|
currentRoom.threadCache.replyId = "";
|
||||||
rightPadding: 0
|
currentRoom.threadCache.threadId = currentRoom.eventIsThreaded(root.eventId) ? currentRoom.rootIdForThread(root.eventId) : root.eventId;
|
||||||
bottomPadding: 0
|
currentRoom.mainCache.clearRelations();
|
||||||
topPadding: 0
|
currentRoom.editCache.clearRelations();
|
||||||
|
RoomManager.requestFullScreenClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QQC2.StackView {
|
Kirigami.Action {
|
||||||
id: stackView
|
visible: !root.hasFileContent && root.author.isLocalMember && root.messageComponentType === MessageComponentType.Text
|
||||||
width: parent.width
|
text: i18n("Edit")
|
||||||
implicitHeight: currentItem.implicitHeight
|
icon.name: "document-edit"
|
||||||
|
onTriggered: {
|
||||||
|
currentRoom.editCache.editId = eventId;
|
||||||
|
currentRoom.mainCache.replyId = "";
|
||||||
|
currentRoom.mainCache.threadId = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Kirigami.Action {
|
||||||
id: nestedActionsComponent
|
visible: (author.isLocalMember || currentRoom.canSendState("redact")) && root.messageComponentType !== MessageComponentType.Other
|
||||||
ColumnLayout {
|
text: i18nc("@action:button", "Remove…")
|
||||||
id: actionLayout
|
icon.name: "edit-delete-remove"
|
||||||
property string title: ""
|
icon.color: "red"
|
||||||
property list<Kirigami.Action> actions
|
onTriggered: {
|
||||||
width: parent.width
|
let dialog = (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||||
spacing: 0
|
title: i18nc("@title:dialog", "Remove Message"),
|
||||||
RowLayout {
|
placeholder: i18nc("@info:placeholder", "Reason for removing this message"),
|
||||||
QQC2.ToolButton {
|
actionText: i18nc("@action:button 'Remove' as in 'Remove this message'", "Remove"),
|
||||||
icon.name: 'draw-arrow-back'
|
icon: "delete"
|
||||||
onClicked: stackView.pop()
|
}, {
|
||||||
}
|
title: i18nc("@title:dialog", "Remove Message"),
|
||||||
Kirigami.Heading {
|
width: Kirigami.Units.gridUnit * 25
|
||||||
level: 3
|
});
|
||||||
Layout.fillWidth: true
|
dialog.accepted.connect(reason => {
|
||||||
text: actionLayout.title
|
currentRoom.redactEvent(root.eventId, reason);
|
||||||
wrapMode: Text.WordWrap
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Repeater {
|
|
||||||
id: listViewAction
|
|
||||||
model: actionLayout.actions
|
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
Kirigami.Action {
|
||||||
icon.name: modelData.icon.name
|
separator: true
|
||||||
icon.color: modelData.icon.color ?? undefined
|
}
|
||||||
enabled: modelData.enabled
|
|
||||||
visible: modelData.visible
|
|
||||||
text: modelData.text
|
|
||||||
onClicked: {
|
|
||||||
modelData.triggered();
|
|
||||||
root.item.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initialItem: ColumnLayout {
|
|
||||||
id: popupContent
|
|
||||||
width: parent.width
|
|
||||||
spacing: 0
|
|
||||||
RowLayout {
|
|
||||||
id: headerLayout
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: Kirigami.Units.largeSpacing
|
|
||||||
spacing: Kirigami.Units.largeSpacing
|
|
||||||
KirigamiComponents.Avatar {
|
|
||||||
id: avatar
|
|
||||||
source: author.avatarUrl
|
|
||||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
|
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
}
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Kirigami.Heading {
|
|
||||||
level: 3
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: author.htmlSafeDisplayName
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
}
|
|
||||||
QQC2.Label {
|
|
||||||
text: plainText
|
|
||||||
Layout.fillWidth: true
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
onLinkActivated: RoomManager.resolveResource(link, "join")
|
Kirigami.Action {
|
||||||
}
|
visible: root.messageComponentType !== MessageComponentType.Other
|
||||||
}
|
text: i18nc("@action:inmenu As in 'Forward this message'", "Forward…")
|
||||||
}
|
icon.name: "mail-forward-symbolic"
|
||||||
Kirigami.Separator {
|
onTriggered: {
|
||||||
Layout.fillWidth: true
|
let page = (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ChooseRoomDialog'), {
|
||||||
}
|
connection: root.connection
|
||||||
Kirigami.Separator {
|
}, {
|
||||||
Layout.fillWidth: true
|
title: i18nc("@title", "Forward Message"),
|
||||||
}
|
width: Kirigami.Units.gridUnit * 25
|
||||||
Repeater {
|
});
|
||||||
id: listViewAction
|
page.chosen.connect(function (targetRoomId) {
|
||||||
model: root.actions
|
root.connection.room(targetRoomId).postHtmlMessage(root.plainText, root.htmlText.length > 0 ? root.htmlText : root.plainText);
|
||||||
|
page.closeDialog();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DelegateChooser {
|
Kirigami.Action {
|
||||||
role: "separator"
|
visible: root.hasFileContent
|
||||||
DelegateChoice {
|
text: {
|
||||||
roleValue: true
|
if (root.messageComponentType === MessageComponentType.Image) {
|
||||||
|
return i18nc("@action:inmenu", "Open Image");
|
||||||
|
} else if (root.messageComponentType === MessageComponentType.Audio) {
|
||||||
|
return i18nc("@action:inmenu", "Open Audio");
|
||||||
|
} else if (root.messageComponentType === MessageComponentType.Video) {
|
||||||
|
return i18nc("@action:inmenu", "Open Video");
|
||||||
|
} else {
|
||||||
|
return i18nc("@action:inmenu", "Open File");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icon.name: "document-open"
|
||||||
|
onTriggered: {
|
||||||
|
currentRoom.openEventMediaExternally(root.eventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FormCard.FormDelegateSeparator {
|
Kirigami.Action {
|
||||||
visible: modelData.visible
|
visible: root.hasFileContent
|
||||||
}
|
text: {
|
||||||
}
|
if (root.messageComponentType === MessageComponentType.Image) {
|
||||||
|
return i18nc("@action:inmenu", "Save Image…");
|
||||||
|
} else if (root.messageComponentType === MessageComponentType.Audio) {
|
||||||
|
return i18nc("@action:inmenu", "Save Audio…");
|
||||||
|
} else if (root.messageComponentType === MessageComponentType.Video) {
|
||||||
|
return i18nc("@action:inmenu", "Save Video…");
|
||||||
|
} else {
|
||||||
|
return i18nc("@action:inmenu", "Save File…");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icon.name: "document-save"
|
||||||
|
onTriggered: {
|
||||||
|
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
|
||||||
|
dialog.selectedFile = currentRoom.fileNameToDownload(eventId);
|
||||||
|
dialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
Kirigami.Action {
|
||||||
roleValue: false
|
visible: root.hasFileContent
|
||||||
|
text: {
|
||||||
|
if (root.messageComponentType === MessageComponentType.Image) {
|
||||||
|
return i18nc("@action:inmenu", "Copy Image");
|
||||||
|
} else if (root.messageComponentType === MessageComponentType.Audio) {
|
||||||
|
return i18nc("@action:inmenu", "Copy Audio");
|
||||||
|
} else if (root.messageComponentType === MessageComponentType.Video) {
|
||||||
|
return i18nc("@action:inmenu", "Copy Video");
|
||||||
|
} else {
|
||||||
|
return i18nc("@action:inmenu", "Copy File");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
icon.name: "edit-copy"
|
||||||
|
onTriggered: {
|
||||||
|
currentRoom.copyEventMedia(root.eventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
Kirigami.Action {
|
||||||
icon.name: modelData.icon.name
|
text: i18nc("@action:inmenu", "Copy Link Address")
|
||||||
icon.color: modelData.icon.color ?? undefined
|
icon.name: "edit-copy"
|
||||||
enabled: modelData.enabled
|
visible: root.hoveredLink.length > 0
|
||||||
visible: modelData.visible
|
onTriggered: Clipboard.saveText(root.hoveredLink)
|
||||||
text: modelData.text
|
}
|
||||||
onClicked: {
|
|
||||||
modelData.triggered();
|
|
||||||
root.item.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
Kirigami.Action {
|
||||||
model: root.nestedActions
|
visible: !root.hasFileContent
|
||||||
|
text: i18nc("@action:inmenu", "Copy Text")
|
||||||
|
icon.name: "edit-copy"
|
||||||
|
onTriggered: Clipboard.saveText(root.selectedText.length > 0 ? root.selectedText : root.plainText)
|
||||||
|
}
|
||||||
|
|
||||||
FormCard.FormButtonDelegate {
|
Kirigami.Action {
|
||||||
action: modelData
|
text: i18nc("@action:inmenu", "Copy Message Link")
|
||||||
visible: modelData.visible
|
icon.name: "link-symbolic"
|
||||||
onClicked: {
|
onTriggered: {
|
||||||
stackView.push(nestedActionsComponent, {
|
Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId);
|
||||||
title: modelData.text,
|
}
|
||||||
actions: modelData.children
|
}
|
||||||
});
|
|
||||||
}
|
Kirigami.Action {
|
||||||
}
|
text: i18nc("@action:button 'Report' as in 'Report this event to the administrators'", "Report…")
|
||||||
}
|
icon.name: "dialog-warning-symbolic"
|
||||||
}
|
visible: !author.isLocalMember
|
||||||
|
onTriggered: {
|
||||||
|
let dialog = (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReasonDialog'), {
|
||||||
|
title: i18nc("@title:dialog", "Report Message"),
|
||||||
|
placeholder: i18nc("@info:placeholder", "Reason for reporting this message"),
|
||||||
|
icon: "dialog-warning-symbolic",
|
||||||
|
actionText: i18nc("@action:button 'Report' as in 'Report this event to the administrators'", "Report")
|
||||||
|
}, {
|
||||||
|
title: i18nc("@title", "Report Message"),
|
||||||
|
width: Kirigami.Units.gridUnit * 25
|
||||||
|
});
|
||||||
|
dialog.accepted.connect(reason => {
|
||||||
|
currentRoom.reportEvent(root.eventId, reason);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
id: webShortcutModelAction
|
||||||
|
|
||||||
|
text: i18nc("@action:inmenu", "Search for '%1'", webShortcutModel.trunkatedSearchText)
|
||||||
|
icon.name: "search-symbolic"
|
||||||
|
visible: !root.hasFileContent && 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: Kirigami.Action {
|
||||||
|
text: model.display
|
||||||
|
icon.name: model.decoration
|
||||||
|
onTriggered: webShortcutModel.trigger(model.edit)
|
||||||
|
}
|
||||||
|
onObjectAdded: (index, object) => webShortcutModelAction.children.push(object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18nc("@action:inmenu", "Configure Web Shortcuts…")
|
||||||
|
icon.name: "configure"
|
||||||
|
visible: !Controller.isFlatpak && webShortcutModel.enabled
|
||||||
|
onTriggered: webShortcutModel.configureWebShortcuts()
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
visible: !root.hasFileContent
|
||||||
|
text: i18nc("@action:inmenu", "Read Text Aloud")
|
||||||
|
icon.name: "audio-speakers-symbolic"
|
||||||
|
onTriggered: {
|
||||||
|
TextToSpeechHelper.speak(i18nc("@info text-to-speech %1 is author %2 is message text", "%1 said %2", root.author.displayName, root.plainText))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
readonly property bool pinned: currentRoom.isEventPinned(root.eventId)
|
||||||
|
|
||||||
|
visible: currentRoom.canSendState("m.room.pinned_events") && root.messageComponentType !== MessageComponentType.Other
|
||||||
|
text: pinned ? i18nc("@action:button 'Unpin' as in 'Unpin this message'", "Unpin") : i18nc("@action:button 'Pin' as in 'Pin the message in the room'", "Pin")
|
||||||
|
icon.name: pinned ? "window-unpin-symbolic" : "pin-symbolic"
|
||||||
|
onTriggered: pinned ? currentRoom.unpinEvent(root.eventId) : currentRoom.pinEvent(root.eventId)
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
separator: true
|
||||||
|
visible: viewSourceAction.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
id: viewSourceAction
|
||||||
|
visible: NeoChatConfig.developerTools
|
||||||
|
text: i18nc("@action:inmenu", "View Source")
|
||||||
|
icon.name: "code-context"
|
||||||
|
onTriggered: RoomManager.viewEventSource(root.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headerContentItem: RowLayout {
|
||||||
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
KirigamiComponents.Avatar {
|
||||||
|
source: root.author.avatarUrl
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: Kirigami.Settings.isMobile ? mobileMenu : regularMenu
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onStatusChanged: if (status == Loader.Ready) {
|
|
||||||
if (Kirigami.Settings.isMobile) {
|
|
||||||
item.open();
|
|
||||||
} else {
|
|
||||||
item.popup();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
import QtCore as Core
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtQuick.Dialogs as Dialogs
|
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 DelegateContextMenu
|
|
||||||
*/
|
|
||||||
DelegateContextMenu {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The MIME type of the media.
|
|
||||||
*/
|
|
||||||
property string mimeType
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Progress info when downloading files.
|
|
||||||
*
|
|
||||||
* @sa Quotient::FileTransferInfo
|
|
||||||
*/
|
|
||||||
required property var progressInfo
|
|
||||||
|
|
||||||
DelegateContextMenu.ReplyMessageAction {}
|
|
||||||
|
|
||||||
Kirigami.Action {
|
|
||||||
separator: true
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Action {
|
|
||||||
text: {
|
|
||||||
if (root.messageComponentType === MessageComponentType.Image) {
|
|
||||||
return i18nc("@action:inmenu", "Open Image");
|
|
||||||
} else if (root.messageComponentType === MessageComponentType.Audio) {
|
|
||||||
return i18nc("@action:inmenu", "Open Audio");
|
|
||||||
} else if (root.messageComponentType === MessageComponentType.Video) {
|
|
||||||
return i18nc("@action:inmenu", "Open Video");
|
|
||||||
} else {
|
|
||||||
return i18nc("@action:inmenu", "Open File");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
icon.name: "document-open"
|
|
||||||
onTriggered: {
|
|
||||||
currentRoom.openEventMediaExternally(root.eventId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Action {
|
|
||||||
text: {
|
|
||||||
if (root.messageComponentType === MessageComponentType.Image) {
|
|
||||||
return i18nc("@action:inmenu", "Save Image…");
|
|
||||||
} else if (root.messageComponentType === MessageComponentType.Audio) {
|
|
||||||
return i18nc("@action:inmenu", "Save Audio…");
|
|
||||||
} else if (root.messageComponentType === MessageComponentType.Video) {
|
|
||||||
return i18nc("@action:inmenu", "Save Video…");
|
|
||||||
} else {
|
|
||||||
return i18nc("@action:inmenu", "Save File…");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
icon.name: "document-save"
|
|
||||||
onTriggered: {
|
|
||||||
var dialog = saveAsDialog.createObject(QQC2.Overlay.overlay);
|
|
||||||
dialog.selectedFile = currentRoom.fileNameToDownload(eventId);
|
|
||||||
dialog.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QQC2.Action {
|
|
||||||
text: {
|
|
||||||
if (root.messageComponentType === MessageComponentType.Image) {
|
|
||||||
return i18nc("@action:inmenu", "Copy Image");
|
|
||||||
} else if (root.messageComponentType === MessageComponentType.Audio) {
|
|
||||||
return i18nc("@action:inmenu", "Copy Audio");
|
|
||||||
} else if (root.messageComponentType === MessageComponentType.Video) {
|
|
||||||
return i18nc("@action:inmenu", "Copy Video");
|
|
||||||
} else {
|
|
||||||
return i18nc("@action:inmenu", "Copy File");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
icon.name: "edit-copy"
|
|
||||||
onTriggered: {
|
|
||||||
currentRoom.copyEventMedia(root.eventId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Kirigami.Action {
|
|
||||||
separator: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DelegateContextMenu.RemoveMessageAction {}
|
|
||||||
|
|
||||||
DelegateContextMenu.PinMessageAction {}
|
|
||||||
|
|
||||||
DelegateContextMenu.ReportMessageAction {}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
|
|
||||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls as QQC2
|
|
||||||
import QtTextToSpeech
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import org.kde.kirigami as Kirigami
|
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
import org.kde.kirigamiaddons.components as KirigamiComponents
|
|
||||||
import org.kde.kirigamiaddons.formcard as FormCard
|
|
||||||
|
|
||||||
import org.kde.neochat
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The menu for normal messages.
|
|
||||||
*
|
|
||||||
* This component just overloads the actions and nested actions of the base menu
|
|
||||||
* to what is required for a message item.
|
|
||||||
*
|
|
||||||
* @sa DelegateContextMenu
|
|
||||||
*/
|
|
||||||
DelegateContextMenu {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The display text of the message as rich text.
|
|
||||||
*/
|
|
||||||
required property string htmlText
|
|
||||||
|
|
||||||
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 {}
|
|
||||||
|
|
||||||
DelegateContextMenu.ReplyThreadMessageAction {}
|
|
||||||
|
|
||||||
Kirigami.Action {
|
|
||||||
visible: root.messageComponentType !== MessageComponentType.Other
|
|
||||||
text: i18nc("@action:inmenu As in 'Forward this message'", "Forward…")
|
|
||||||
icon.name: "mail-forward-symbolic"
|
|
||||||
onTriggered: {
|
|
||||||
let page = (root.Kirigami.PageStack.pageStack as Kirigami.PageRow).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 {
|
|
||||||
visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent
|
|
||||||
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: "link-symbolic"
|
|
||||||
onTriggered: {
|
|
||||||
Clipboard.saveText("https://matrix.to/#/" + currentRoom.id + "/" + root.eventId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QQC2.Action {
|
|
||||||
text: i18nc("@action:inmenu", "Read Text Aloud")
|
|
||||||
icon.name: "audio-speakers-symbolic"
|
|
||||||
onTriggered: {
|
|
||||||
TextToSpeechHelper.speak(i18nc("@info text-to-speech %1 is author %2 is message text", "%1 said %2", root.author.displayName, root.plainText))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kirigami.Action {
|
|
||||||
separator: true
|
|
||||||
}
|
|
||||||
DelegateContextMenu.PinMessageAction {}
|
|
||||||
DelegateContextMenu.ReportMessageAction {}
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user