Depends on https://github.com/quotient-im/libQuotient/pull/695 Currently basic just to show a working implementation using RoomMember. Currently only the room event and search models are moved over. Will change everything else over once the dependent pr is complete.
362 lines
13 KiB
QML
362 lines
13 KiB
QML
// 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 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
|
|
|
|
/**
|
|
* @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
|
|
|
|
/**
|
|
* @brief The current 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.
|
|
*
|
|
* A Quotient::RoomMember object.
|
|
*
|
|
* @sa Quotient::RoomMember
|
|
*/
|
|
required property var author
|
|
|
|
/**
|
|
* @brief The display text of the message as plain text.
|
|
*/
|
|
required property string plainText
|
|
|
|
/**
|
|
* @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
|
|
|
|
/**
|
|
* Some common actions shared between menus
|
|
*/
|
|
component ViewSourceAction: Kirigami.Action {
|
|
visible: Config.developerTools
|
|
text: i18n("View Source")
|
|
icon.name: "code-context"
|
|
onTriggered: RoomManager.viewEventSource(root.eventId)
|
|
}
|
|
|
|
component RemoveMessageAction: Kirigami.Action {
|
|
visible: author.isLocalMember || currentRoom.canSendState("redact")
|
|
text: i18n("Remove")
|
|
icon.name: "edit-delete-remove"
|
|
icon.color: "red"
|
|
onTriggered: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'RemoveSheet'), {
|
|
room: currentRoom,
|
|
eventId: eventId
|
|
}, {
|
|
title: i18nc("@title", "Remove Message"),
|
|
width: Kirigami.Units.gridUnit * 25
|
|
})
|
|
}
|
|
|
|
component ReplyMessageAction: Kirigami.Action {
|
|
text: i18n("Reply")
|
|
icon.name: "mail-replied-symbolic"
|
|
onTriggered: {
|
|
currentRoom.mainCache.replyId = eventId;
|
|
currentRoom.editCache.editId = "";
|
|
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: applicationWindow().pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'ReportSheet'), {
|
|
room: currentRoom,
|
|
eventId: eventId
|
|
}, {
|
|
title: i18nc("@title", "Report Message"),
|
|
width: Kirigami.Units.gridUnit * 25
|
|
})
|
|
}
|
|
|
|
Component {
|
|
id: regularMenu
|
|
|
|
QQC2.Menu {
|
|
id: menu
|
|
Instantiator {
|
|
model: root.nestedActions
|
|
delegate: QQC2.Menu {
|
|
id: menuItem
|
|
visible: modelData.visible
|
|
title: modelData.text
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
model: root.actions
|
|
QQC2.MenuItem {
|
|
visible: modelData.visible
|
|
action: modelData
|
|
onClicked: root.item.close()
|
|
}
|
|
}
|
|
QQC2.Menu {
|
|
id: webshortcutmenu
|
|
title: i18n("Search for '%1'", webshortcutmodel.trunkatedSearchText)
|
|
property bool isVisible: webshortcutmodel.enabled
|
|
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: RoomManager.resolveResource(url)
|
|
}
|
|
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 {
|
|
id: mobileMenu
|
|
|
|
Kirigami.OverlayDrawer {
|
|
id: drawer
|
|
height: stackView.implicitHeight
|
|
edge: Qt.BottomEdge
|
|
padding: 0
|
|
leftPadding: 0
|
|
rightPadding: 0
|
|
bottomPadding: 0
|
|
topPadding: 0
|
|
|
|
parent: applicationWindow().overlay
|
|
|
|
QQC2.StackView {
|
|
id: stackView
|
|
width: parent.width
|
|
implicitHeight: currentItem.implicitHeight
|
|
|
|
Component {
|
|
id: nestedActionsComponent
|
|
ColumnLayout {
|
|
id: actionLayout
|
|
property string title: ""
|
|
property list<Kirigami.Action> actions
|
|
width: parent.width
|
|
spacing: 0
|
|
RowLayout {
|
|
QQC2.ToolButton {
|
|
icon.name: 'draw-arrow-back'
|
|
onClicked: stackView.pop()
|
|
}
|
|
Kirigami.Heading {
|
|
level: 3
|
|
Layout.fillWidth: true
|
|
text: actionLayout.title
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
}
|
|
Repeater {
|
|
id: listViewAction
|
|
model: actionLayout.actions
|
|
|
|
FormCard.FormButtonDelegate {
|
|
icon.name: modelData.icon.name
|
|
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.avatarSource
|
|
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: currentRoom.htmlSafeMemberName(author.id)
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
QQC2.Label {
|
|
text: plainText
|
|
Layout.fillWidth: true
|
|
wrapMode: Text.WordWrap
|
|
|
|
onLinkActivated: RoomManager.resolveResource(link, "join")
|
|
}
|
|
}
|
|
}
|
|
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
|
|
}
|
|
Repeater {
|
|
id: listViewAction
|
|
model: root.actions
|
|
|
|
FormCard.FormButtonDelegate {
|
|
icon.name: modelData.icon.name
|
|
icon.color: modelData.icon.color ?? undefined
|
|
enabled: modelData.enabled
|
|
visible: modelData.visible
|
|
text: modelData.text
|
|
onClicked: {
|
|
modelData.triggered();
|
|
root.item.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
model: root.nestedActions
|
|
|
|
FormCard.FormButtonDelegate {
|
|
action: modelData
|
|
visible: modelData.visible
|
|
onClicked: {
|
|
stackView.push(nestedActionsComponent, {
|
|
title: modelData.text,
|
|
actions: modelData.children
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|