Files
neochat/src/messagecontent/TextComponent.qml
James Graham 8e516422b7 Make sure the default menu of textArea isn't thrown for non editable TextComponents.
Note: I know this is horrible but it's all we got until discussions in QQC2-Desktop-Style are resolved.
2026-02-22 18:07:27 +00:00

175 lines
5.4 KiB
QML

// SPDX-FileCopyrightText: 2020 Black Hat <bhat@encom.eu.org>
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// 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.neochat
/**
* @brief A component to show rich text from a message.
*/
QQC2.TextArea {
id: root
/**
* @brief The index of the delegate in the model.
*/
required property int index
/**
* @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 NeochatRoomMember author
/**
* @brief The display text of the message.
*/
required property string display
/**
* @brief Whether the component should be editable.
*/
required property bool editable
onEditableChanged: manageDefaultMenus()
/**
* @brief The attributes of the component.
*/
required property var componentAttributes
readonly property ChatTextItemHelper chatTextItemHelper: componentAttributes?.chatTextItemHelper ?? null
onChatTextItemHelperChanged: if (chatTextItemHelper) {
chatTextItemHelper.textItem = root;
}
/**
* @brief Whether the component is currently focussed.
*/
required property bool currentFocus
onCurrentFocusChanged: if (currentFocus && !focus) {
forceActiveFocus();
}
/**
* @brief Whether the message contains a spoiler
*/
readonly property var hasSpoiler: root.componentAttributes?.hasSpoiler ?? false
/**
* @brief Whether this message is replying to another.
*/
property bool isReply: false
Layout.fillWidth: NeoChatConfig.compactLayout
Layout.maximumWidth: Message.maxContentWidth
Keys.onPressed: (event) => {
event.accepted = Message.contentModel.keyHelper.handleKey(event.key, event.modifiers);
}
onFocusChanged: if (focus && !currentFocus && editable) {
Message.contentModel.setFocusRow(index, true)
}
ListView.onReused: Qt.binding(() => !hasSpoiler.test(display))
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
text: root.editable ? "" : display
color: Kirigami.Theme.textColor
selectedTextColor: Kirigami.Theme.highlightedTextColor
selectionColor: Kirigami.Theme.highlightColor
font {
pointSize: !root.isReply && QmlUtils.isEmoji(display)
? Kirigami.Theme.defaultFont.pointSize * 4 * NeoChatConfig.fontScale
: Kirigami.Theme.defaultFont.pointSize * NeoChatConfig.fontScale
family: QmlUtils.isEmoji(display) ? 'emoji' : Kirigami.Theme.defaultFont.family
}
selectByMouse: !Kirigami.Settings.isMobile
readOnly: !root.editable
wrapMode: Text.Wrap
textFormat: Text.RichText
placeholderText: if (!editable || index !== (Message.contentModel?.hasAttachment ? 1 : 0)) {
return "";
} else if (Message.contentModel?.hasAttachment) {
i18nc("@placeholder", "Set an attachment caption…")
} else if (Message.room?.usesEncryption) {
i18nc("@placeholder", "Send an encrypted message…")
} else {
i18nc("@placeholder", "Send a message…")
}
onLinkActivated: link => {
if (!root.editable) {
RoomManager.resolveResource(link, "join");
}
}
onHoveredLinkChanged: if (hoveredLink.length > 0 && hoveredLink !== "1") {
(QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = hoveredLink;
} else {
(QQC2.ApplicationWindow.window as Main).hoverLinkIndicator.text = "";
}
Component.onCompleted: manageDefaultMenus()
HoverHandler {
cursorShape: root.hoveredLink || (!(root.componentAttributes?.spoilerRevealed ?? false) && root.hasSpoiler) ? Qt.PointingHandCursor : Qt.IBeamCursor
}
TapHandler {
enabled: !root.hoveredLink && root.hasSpoiler
onTapped: root.Message.contentModel.toggleSpoiler(root.Message.contentFilterModel.mapToSource(root.Message.contentFilterModel.index(root.index, 0)))
}
TapHandler {
enabled: !root.hoveredLink && !root.editable
acceptedButtons: Qt.LeftButton
acceptedDevices: PointerDevice.TouchScreen
onLongPressed: {
requestMenu();
}
}
TapHandler {
enabled: !root.editable
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
onTapped: {
requestMenu();
}
}
function requestMenu() {
const event = root.Message.room.findEvent(root.eventId);
RoomManager.viewEventMenu(root.QQC2.Overlay.overlay, event, root.Message.room, root.Message.selectedText, root.Message.hoveredLink);
}
// TODO - Remove this once the state of TextArea is sorted in QQC2
// This is horrible I know I hate it but currently seemingly the only way to stop the default
// menus in TextArea see https://invent.kde.org/frameworks/qqc2-desktop-style/-/issues/15
function manageDefaultMenus(): void {
for (let i = 0; i < resources.length; i++) {
if (resources[i] instanceof TapHandler) {
(resources[i] as TapHandler).enabled = root.editable;
return;
}
}
}
background: null
}