Page MenuHomePhorge

No OneTemporary

Size
16 KB
Referenced Files
None
Subscribers
None
diff --git a/src/contents/ui/Bubble.qml b/src/contents/ui/Bubble.qml
index 539735e..5aac8c4 100644
--- a/src/contents/ui/Bubble.qml
+++ b/src/contents/ui/Bubble.qml
@@ -1,190 +1,202 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.kirigami 2.13 as Kirigami
import '.' as Kazv
ItemDelegate {
id: upper
default property var children
property var currentEvent: event
property var menuContent: []
readonly property var bubbleSpacing: leftPadding + rightPadding
Layout.fillWidth: true
Layout.preferredHeight: bubbleRootLayout.implicitHeight
property var backgroundItem: Rectangle {
anchors.fill: parent
color: hovered ? Kirigami.Theme.activeBackgroundColor : Kirigami.Theme.backgroundColor
}
background: compactMode ? null : backgroundItem
property var eventSourcePopup: Kirigami.OverlaySheet {
title: l10n.get('event-source-popup-title')
Kazv.EventSourceView {
event: upper.currentEvent
}
}
property var reactionPopup: Kazv.ReactToEventPopup {
onAccepted: eventView.reactWith(text)
}
property var menu: Menu {
objectName: 'bubbleContextMenu'
property list<QtObject> staticItems: [
Kirigami.Action {
objectName: 'replyToMenuItem'
text: l10n.get('event-reply-action')
onTriggered: setDraftReplyTo(currentEvent.eventId)
enabled: event && !event.redacted
},
Kirigami.Action {
objectName: 'deleteMenuItem'
text: l10n.get('event-delete')
onTriggered: eventView.redactSelf()
enabled: event && !event.redacted
},
Kirigami.Action {
objectName: 'reactMenuItem'
text: l10n.get('event-react-action')
onTriggered: reactionPopup.open()
enabled: event && !event.redacted
},
MenuSeparator {},
Kirigami.Action {
text: l10n.get('event-view-source')
onTriggered: eventSourcePopup.open()
}
]
contentData: Array.from(staticItems).concat(upper.menuContent)
}
function shouldPopupMenu() {
return !compactMode
}
function maybePopupMenu() {
if (shouldPopupMenu()) {
menu.popup(parent)
}
}
RowLayout {
id: bubbleRootLayout
anchors.left: parent.left
anchors.right: parent.right
property var replyToOrAnnotatedEventId: currentEvent.replyingToEventId || (currentEvent.relationType === 'm.annotation' ? currentEvent.relatedEventId : '')
ColumnLayout {
Layout.fillWidth: true
- property var inReplyTo: RowLayout {
+ property var inReplyTo: Item {
Layout.fillWidth: true
Layout.margins: 0
+ Layout.minimumHeight: Math.min(inReplyToLayout.implicitHeight, Kirigami.Units.gridUnit * 5)
+ Layout.maximumHeight: Kirigami.Units.gridUnit * 5
+ clip: true
+
+ RowLayout {
+ id: inReplyToLayout
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ Rectangle {
+ Layout.fillHeight: true
+ Layout.preferredWidth: Kirigami.Units.smallSpacing
+ color: Kirigami.Theme.activeTextColor
+ clip: true
+ }
- Rectangle {
- Layout.fillHeight: true
- Layout.preferredWidth: Kirigami.Units.smallSpacing
- color: Kirigami.Theme.activeTextColor
- }
-
- Loader {
- id: inReplyToLoader
- source: 'qrc:/EventViewCompact.qml'
- active: bubbleRootLayout.replyToOrAnnotatedEventId && !compactMode
- asynchronous: true
- Layout.minimumHeight: inReplyToLoader.item ? inReplyToLoader.item.height : 0
- Layout.fillWidth: true
-
- property var event: room.messageById(bubbleRootLayout.replyToOrAnnotatedEventId)
- property var props: ({
- event,
- sender: room.member(event.sender || matrixSdk.userId),
- stateKeyUser: event.stateKey ? room.member(event.stateKey) : {},
- isGapped: timeline.gaps.includes(event.eventId),
- })
+ Loader {
+ id: inReplyToLoader
+ clip: true
+ source: 'qrc:/EventViewCompact.qml'
+ active: bubbleRootLayout.replyToOrAnnotatedEventId && !compactMode
+ asynchronous: true
+ Layout.minimumHeight: inReplyToLoader.item ? inReplyToLoader.item.height : 0
+ Layout.fillWidth: true
+
+ property var event: room.messageById(bubbleRootLayout.replyToOrAnnotatedEventId)
+ property var props: ({
+ event,
+ sender: room.member(event.sender || matrixSdk.userId),
+ stateKeyUser: event.stateKey ? room.member(event.stateKey) : {},
+ isGapped: timeline.gaps.includes(event.eventId),
+ })
+ }
}
}
-
children: [
...(bubbleRootLayout.replyToOrAnnotatedEventId && !compactMode ? [inReplyTo] : []),
...(Array.isArray(upper.children) ? upper.children :
upper.children ? [upper.children] : []),
]
}
property var popupAction: Kirigami.Action {
id: popupAction
text: l10n.get('event-popup-action')
iconName: 'view-more-horizontal-symbolic'
onTriggered: maybePopupMenu()
}
RowLayout {
Layout.alignment: Qt.AlignBottom
Kirigami.Icon {
source: 'emblem-encrypted-locked'
visible: !compactMode && event && event.encrypted
Layout.preferredHeight: inlineBadgeSize
Layout.preferredWidth: inlineBadgeSize
Accessible.role: Accessible.StaticText
Accessible.name: l10n.get('event-encrypted')
ToolTip.text: l10n.get('event-encrypted')
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hoverHandlerEncIcon.hovered
HoverHandler { id: hoverHandlerEncIcon }
}
Kirigami.Icon {
objectName: 'localEchoIndicator'
visible: !!event.isLocalEcho
source: event.isSending ? 'state-sync' : 'state-warning'
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Accessible.role: event.isSending ? Accessible.StaticText : Accessible.Button
Accessible.name: event.isSending ? l10n.get('event-sending') : l10n.get('event-resend')
ToolTip.text: event.isSending ? l10n.get('event-sending') : l10n.get('event-send-failed')
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hoverHandler.hovered
HoverHandler { id: hoverHandler }
TapHandler {
objectName: 'resendEventButton'
onTapped: {
room.resendMessage(event.txnId);
}
enabled: event.isFailed
}
}
Label {
objectName: 'timeIndicator'
visible: !compactMode && !event.isLocalEcho
text: event.formattedTime
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.8
}
ToolButton {
id: moreButton
visible: !compactMode
action: popupAction
display: AbstractButton.IconOnly
}
}
}
}
diff --git a/src/contents/ui/EventView.qml b/src/contents/ui/EventView.qml
index aeddd45..1b744fc 100644
--- a/src/contents/ui/EventView.qml
+++ b/src/contents/ui/EventView.qml
@@ -1,266 +1,266 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.2
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import Qt.labs.qmlmodels 1.0
import org.kde.kirigami 2.13 as Kirigami
import 'event-types' as Types
Item {
id: eventView
property var event
property var sender
property var stateKeyUser
property var messageType: getMessageType(event)
property var iconSize: Kirigami.Units.iconSizes.large
property var inlineBadgeSize: Kirigami.Units.iconSizes.smallMedium
property var senderNameSize: Kirigami.Units.gridUnit * 1.2
property var redactPromise: null
property var minHeight: Kirigami.Units.gridUnit * 2
property var isGapped: false
property var compactMode: false
property var calculatedHeight: (gappedLabel.visible ? gappedLabel.height : 0) + (loader.item ? loader.item.implicitHeight : 0)
height: calculatedHeight
implicitHeight: calculatedHeight
Layout.minimumHeight: calculatedHeight
Layout.preferredHeight: calculatedHeight
Component {
id: textEV
Types.Text {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: emoteEV
Types.Emote {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: noticeEV
Types.Notice {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: stateEV
Types.State {
event: eventView.event
sender: eventView.sender
stateKeyUser: eventView.stateKeyUser
}
}
Component {
id: imageEV
Types.Image {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: fileEV
Types.File {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: videoEV
Types.Video {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: audioEV
Types.Audio {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: unknownEV
Label {
text: 'unknown event'
}
}
Component {
id: redactedEV
Types.Redacted {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: reactionEV
Types.Reaction {
event: eventView.event
sender: eventView.sender
}
}
Component {
id: ignoreEV
Item {
}
}
ToolButton {
id: gappedLabel
- visible: eventView.isGapped
+ visible: eventView.isGapped && !eventView.compactMode
icon.name: 'content-loading-symbolic'
text: l10n.get('room-timeline-load-more-action')
anchors.top: eventView.top
anchors.bottom: loader.top
anchors.left: eventView.left
anchors.right: eventView.right
onClicked: eventView.paginateBack()
}
Loader {
sourceComponent: getSource(messageType)
id: loader
anchors.left: eventView.left
anchors.right: eventView.right
anchors.bottom: eventView.bottom
}
function getSource(t) {
switch (t) {
case 'text':
return textEV;
case 'emote':
return emoteEV;
case 'notice':
return noticeEV;
case 'state':
return stateEV;
case 'image':
return imageEV;
case 'file':
return fileEV;
case 'video':
return videoEV;
case 'audio':
return audioEV;
case 'redacted':
return redactedEV;
case 'reaction':
return reactionEV;
case 'ignore':
return ignoreEV;
default:
return unknownEV;
}
}
function getMessageType(e) {
if (e.redacted) {
return 'redacted';
}
if (e.isState) {
return 'state';
}
switch (e.type) {
case 'm.room.message':
switch (e.content.msgtype) {
case 'm.text':
return 'text';
case 'm.emote':
return 'emote';
case 'm.notice':
return 'notice';
case 'm.image':
return 'image';
case 'm.file':
return 'file';
case 'm.audio':
return 'audio';
case 'm.video':
return 'video';
case 'm.location':
return 'location';
default:
console.log('msg type=unknown');
return 'unknown';
}
case 'm.room.redaction':
return 'ignore';
case 'm.reaction':
return 'reaction';
default:
return 'unknown';
}
}
function redactSelf(reason) {
eventView.redactPromise = room.redactEvent(eventView.event.eventId, reason);
}
Connections {
target: eventView.redactPromise
function onResolved(success, data) {
if (!success) {
showPassiveNotification(l10n.get('event-delete-failed', { errorMsg: data.error, errorCode: data.errorCode }));
}
eventView.redactPromise = null;
}
}
function paginateBack() {
room.paginateBackFrom(event.eventId);
}
function reactWith(reactionText) {
room.sendReaction(reactionText, event.eventId);
}
}
diff --git a/src/contents/ui/SendMessageBox.qml b/src/contents/ui/SendMessageBox.qml
index a4bb429..954da10 100644
--- a/src/contents/ui/SendMessageBox.qml
+++ b/src/contents/ui/SendMessageBox.qml
@@ -1,132 +1,143 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import QtQuick.Dialogs 1.3
import org.kde.kirigami 2.13 as Kirigami
import moe.kazv.mxc.kazv 0.0 as MK
import '.' as Kazv
ColumnLayout {
id: sendMessageBox
property var room
property var draftReplyTo: ''
property var timeline: room.timeline()
onRoomChanged: {
textArea.changeText(room.localDraft, true);
}
ColumnLayout {
visible: !!sendMessageBox.draftReplyTo
RowLayout {
Label {
Layout.fillWidth: true
text: l10n.get('send-message-box-reply-to')
}
ToolButton {
action: removeReplyToAction
display: AbstractButton.IconOnly
}
}
- Kazv.EventViewWrapper {
- Layout.minimumHeight: implicitHeight
+ Item {
+ Layout.minimumHeight: Math.min(replyToEventView.implicitHeight, Kirigami.Units.gridUnit * 5)
+ Layout.maximumHeight: Kirigami.Units.gridUnit * 5
Layout.fillWidth: true
- event: room.messageById(sendMessageBox.draftReplyTo)
- compactMode: true
+ clip: true
+
+ Kazv.EventViewWrapper {
+ id: replyToEventView
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ event: room.messageById(sendMessageBox.draftReplyTo)
+ compactMode: true
+ }
}
}
RowLayout {
TextArea {
id: textArea
objectName: 'draftMessage'
property var shortcutList: ["Ctrl+Return", "Ctrl+Enter"]
property var inhibitTyping: false
placeholderText: l10n.get('send-message-box-input-placeholder')
Layout.fillWidth: true
wrapMode: TextEdit.Wrap
onTextChanged: {
room.setLocalDraft(text);
if (!inhibitTyping) {
room.setTyping(true);
}
inhibitTyping = false;
}
function changeText(newText, inhibitTyping) {
textArea.inhibitTyping = inhibitTyping;
textArea.text = newText;
}
onVisibleChanged: {
if (!visible) {
room.updateLocalDraftNow();
}
}
// Shortcut keys for sending messages (TODO: Shortcut keys customized by the user)
Shortcut {
sequences: textArea.shortcutList
onActivated: {
sendAction.trigger()
}
}
}
ToolButton {
icon.name: "document-send-symbolic"
onClicked: sendMediaFileAction.trigger()
}
ToolButton {
icon.name: "document-send"
onClicked: sendAction.trigger()
}
}
Kirigami.Action {
id: removeReplyToAction
iconName: 'window-close-symbolic'
text: l10n.get('send-message-box-remove-reply-to-action')
onTriggered: {
sendMessageBox.draftReplyTo = '';
}
}
Kirigami.Action {
id: sendAction
iconName: "document-send"
text: l10n.get("send-message-box-send")
onTriggered: {
room.setTyping(false);
room.sendTextMessage(textArea.text, draftReplyTo);
textArea.changeText("", true);
draftReplyTo = '';
}
}
Kirigami.Action {
id:sendMediaFileAction
iconName: "mail-attachment-symbolic"
text: l10n.get("send-message-box-send-file")
onTriggered: {
fileDialog.open()
}
}
property var fileDialog: FileDialog {
onAccepted: {
kazvIOManager.startNewUploadJob(matrixSdk.serverUrl, fileUrl, matrixSdk.token,
room.roomId, sdkVars.roomList, room.encrypted)
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Oct 11, 1:42 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785833
Default Alt Text
(16 KB)

Event Timeline