Use kirigami-addons maximise components

Use new kirigami-addons MaximizeImage.qml to replace local FullScreenImage.qml

depends upon libraries/kirigami-addons!88

TODO
- [x] Remove the old `fullscreenimage.qml` before merging as no longer needed

Implements #571
This commit is contained in:
James Graham
2023-04-19 21:10:30 +00:00
committed by Tobias Fella
parent 4002bb804c
commit 144dc1f8f4
6 changed files with 135 additions and 343 deletions

View File

@@ -1,312 +0,0 @@
// SPDX-FileCopyrightText: 2019 Black Hat <bhat@encom.eu.org>
// SPDX-License-Identifier: GPL-3.0-only
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1
import org.kde.kirigami 2.15 as Kirigami
import org.kde.neochat 1.0
QQC2.Popup {
id: root
property alias source: image.source
property string filename
property string blurhash: ""
property int imageWidth: -1
property int imageHeight: -1
property var modelData
parent: QQC2.Overlay.overlay
closePolicy: QQC2.Popup.CloseOnEscape
width: parent.width
height: parent.height
modal: true
padding: 0
background: null
ColumnLayout {
anchors.fill: parent
spacing: Kirigami.Units.largeSpacing
QQC2.Control {
Layout.fillWidth: true
contentItem: RowLayout {
spacing: Kirigami.Units.largeSpacing
Kirigami.Avatar {
id: avatar
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
name: modelData.author.name ?? modelData.author.displayName
source: modelData.author.avatarMediaId ? ("image://mxc/" + modelData.author.avatarMediaId) : ""
color: modelData.author.color
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
QQC2.Label {
id: nameLabel
text: modelData.author.displayName
textFormat: Text.PlainText
font.weight: Font.Bold
color: author.color
}
QQC2.Label {
id: timeLabel
text: time.toLocaleString(Qt.locale(), Locale.ShortFormat)
}
}
QQC2.Label {
id: imageLabel
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.largeSpacing
text: modelData.display
font.weight: Font.Bold
elide: Text.ElideRight
}
QQC2.ToolButton {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
text: i18n("Zoom in")
Accessible.name: text
icon.name: "zoom-in"
display: QQC2.AbstractButton.IconOnly
onClicked: {
image.scaleFactor = image.scaleFactor + 0.25
if (image.scaleFactor > 3) {
image.scaleFactor = 3
}
}
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
text: i18n("Zoom out")
Accessible.name: text
icon.name: "zoom-out"
display: QQC2.AbstractButton.IconOnly
onClicked: {
image.scaleFactor = image.scaleFactor - 0.25
if (image.scaleFactor < 0.25) {
image.scaleFactor = 0.25
}
}
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
text: i18n("Rotate left")
Accessible.name: text
icon.name: "image-rotate-left-symbolic"
display: QQC2.AbstractButton.IconOnly
onClicked: image.rotationAngle = image.rotationAngle - 90
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
text: i18n("Rotate right")
Accessible.name: text
icon.name: "image-rotate-right-symbolic"
display: QQC2.AbstractButton.IconOnly
onClicked: image.rotationAngle = image.rotationAngle + 90
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
text: i18n("Save as")
Accessible.name: text
icon.name: "document-save"
display: QQC2.AbstractButton.IconOnly
onClicked: {
var dialog = saveAsDialog.createObject(QQC2.ApplicationWindow.overlay)
dialog.open()
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(eventId)
}
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
QQC2.ToolButton {
Layout.preferredWidth: Kirigami.Units.gridUnit * 2
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
text: i18n("Close")
Accessible.name: text
icon.name: "dialog-close"
display: QQC2.AbstractButton.IconOnly
onClicked: {
root.close()
}
QQC2.ToolTip.text: text
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
}
background: Rectangle {
color: Kirigami.Theme.alternateBackgroundColor
}
Kirigami.Separator {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: 1
}
}
QQC2.BusyIndicator {
Layout.fillWidth: true
visible: image.status !== Image.Ready && root.blurhash === ""
running: visible
}
// Provides container to fill the space that isn't taken up by the top controls and clips the image when zooming makes it larger than the available area.
Item {
id: imageContainer
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.bottomMargin: Kirigami.Units.largeSpacing
clip: true
AnimatedImage {
id: image
property var scaleFactor: 1
property int rotationAngle: 0
property var rotationInsensitiveWidth: Math.min(root.imageWidth > 0 ? root.imageWidth : sourceSize.width, imageContainer.width - Kirigami.Units.largeSpacing * 2)
property var rotationInsensitiveHeight: Math.min(root.imageHeight > 0 ? root.imageHeight : sourceSize.height, imageContainer.height - Kirigami.Units.largeSpacing * 2)
anchors.centerIn: parent
width: rotationAngle % 180 === 0 ? rotationInsensitiveWidth : rotationInsensitiveHeight
height: rotationAngle % 180 === 0 ? rotationInsensitiveHeight : rotationInsensitiveWidth
fillMode: Image.PreserveAspectFit
clip: true
Behavior on width {
NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic}
}
Behavior on height {
NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic}
}
Image {
anchors.centerIn: parent
width: image.width
height: image.height
source: root.blurhash !== "" ? ("image://blurhash/" + root.blurhash) : ""
visible: root.blurhash !== "" && parent.status !== Image.Ready
}
transform: [
Rotation {
origin.x: image.width / 2
origin.y: image.height / 2
angle: image.rotationAngle
Behavior on angle {
RotationAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic}
}
},
Scale {
origin.x: image.width / 2
origin.y: image.height / 2
xScale: image.scaleFactor
yScale: image.scaleFactor
Behavior on xScale {
NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic}
}
Behavior on yScale {
NumberAnimation {duration: Kirigami.Units.longDuration; easing.type: Easing.InOutCubic}
}
}
]
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
const contextMenu = fileDelegateContextMenu.createObject(parent, {
author: modelData.author,
message: modelData.message,
eventId: modelData.eventId,
source: modelData.source,
file: root.parent,
mimeType: modelData.mimeType,
progressInfo: modelData.progressInfo,
plainMessage: modelData.message,
});
contextMenu.closeFullscreen.connect(root.close)
contextMenu.open();
}
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
root.close()
}
}
}
}
Component {
id: saveAsDialog
FileDialog {
fileMode: FileDialog.SaveFile
folder: Config.lastSaveDirectory.length > 0 ? Config.lastSaveDirectory : StandardPaths.writableLocation(StandardPaths.DownloadLocation)
onAccepted: {
Config.lastSaveDirectory = folder
Config.save()
if (!currentFile) {
return;
}
currentRoom.downloadFile(eventId, currentFile)
}
}
}
onClosed: {
image.scaleFactor = 1
image.rotationAngle = 0
}
}

View File

@@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1
import org.kde.kirigami 2.13 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as Components
import org.kde.neochat 1.0
Components.AlbumMaximizeComponent {
id: root
property var modelData
property list<Components.AlbumModelItem> items: [
Components.AlbumModelItem {
type: root.modelData.delegateType === MessageEventModel.Image ? Components.AlbumModelItem.Image : Components.AlbumModelItem.Video
source: root.modelData.delegateType === MessageEventModel.Video ? modelData.progressInfo.localPath : modelData.mediaUrl
tempSource: modelData.content.info["xyz.amorgan.blurhash"] ? ("image://blurhash/" + modelData.content.info["xyz.amorgan.blurhash"]) : ""
caption: modelData.display
}
]
model: items
initialIndex: 0
leading: RowLayout {
Kirigami.Avatar {
id: userAvatar
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
name: modelData.author.name ?? modelData.author.displayName
source: modelData.author.avatarMediaId ? ("image://mxc/" + modelData.author.avatarMediaId) : ""
color: modelData.author.color
}
ColumnLayout {
spacing: 0
QQC2.Label {
id: userLabel
text: modelData.author.name ?? modelData.author.displayName
color: modelData.author.color
font.weight: Font.Bold
elide: Text.ElideRight
}
QQC2.Label {
id: dateTimeLabel
text: modelData.time.toLocaleString(Qt.locale(), Locale.ShortFormat)
color: Kirigami.Theme.disabledTextColor
elide: Text.ElideRight
}
}
}
onItemRightClicked: {
const contextMenu = fileDelegateContextMenu.createObject(parent, {
author: modelData.author,
message: modelData.message,
eventId: modelData.eventId,
source: modelData.source,
file: parent,
mimeType: modelData.mimeType,
progressInfo: modelData.progressInfo,
plainMessage: modelData.message,
});
contextMenu.closeFullscreen.connect(root.close)
contextMenu.open();
}
onSaveItem: {
var dialog = saveAsDialog.createObject(QQC2.ApplicationWindow.overlay)
dialog.open()
dialog.currentFile = dialog.folder + "/" + currentRoom.fileNameToDownload(modelData.eventId)
}
Component {
id: saveAsDialog
FileDialog {
fileMode: FileDialog.SaveFile
folder: root.saveFolder
onAccepted: {
Config.lastSaveDirectory = folder
Config.save()
if (!currentFile) {
return;
}
currentRoom.downloadFile(eventId, currentFile)
}
}
}
}

View File

@@ -4,9 +4,10 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2 import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import Qt.labs.platform 1.1 import QtQml.Models 2.15
import org.kde.kirigami 2.15 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as Components
import org.kde.neochat 1.0 import org.kde.neochat 1.0
@@ -115,37 +116,27 @@ TimelineContainer {
} }
} }
Component {
id: fileDialog
FileDialog {
fileMode: FileDialog.SaveFile
folder: StandardPaths.writableLocation(StandardPaths.DownloadLocation)
onAccepted: {
currentRoom.downloadFile(eventId, file)
}
}
}
TapHandler { TapHandler {
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onTapped: { onTapped: {
img.QQC2.ToolTip.hide() img.QQC2.ToolTip.hide()
img.paused = true img.paused = true
fullScreenImage.open() imageDelegate.ListView.view.interactive = false
var popup = maximizeImageComponent.createObject(QQC2.ApplicationWindow.overlay, {
modelData: model,
})
popup.closed.connect(() => {
imageDelegate.ListView.view.interactive = true
img.paused = false
popup.destroy()
})
popup.open()
} }
} }
FullScreenImage { Component {
id: fullScreenImage id: maximizeImageComponent
filename: eventId NeochatMaximizeComponent {}
source: mediaUrl
blurhash: model.content.info["xyz.amorgan.blurhash"]
imageWidth: content.info.w
imageHeight: content.info.h
modelData: model
onClosed: img.paused = false
} }
function downloadAndOpen() { function downloadAndOpen() {

View File

@@ -8,6 +8,7 @@ import QtMultimedia 5.15
import Qt.labs.platform 1.1 as Platform import Qt.labs.platform 1.1 as Platform
import org.kde.kirigami 2.13 as Kirigami import org.kde.kirigami 2.13 as Kirigami
import org.kde.kirigamiaddons.labs.components 1.0 as Components
import org.kde.neochat 1.0 import org.kde.neochat 1.0
@@ -310,6 +311,31 @@ TimelineContainer {
} }
} }
} }
QQC2.ToolButton {
id: maximizeButton
display: QQC2.AbstractButton.IconOnly
action: Kirigami.Action {
text: i18n("Maximize")
icon.name: "view-fullscreen"
onTriggered: {
videoDelegate.ListView.view.interactive = false
vid.pause()
var popup = maximizeVideoComponent.createObject(QQC2.ApplicationWindow.overlay, {
modelData: model,
})
popup.closed.connect(() => {
videoDelegate.ListView.view.interactive = true
popup.destroy()
})
popup.open()
}
}
}
Component {
id: maximizeVideoComponent
NeochatMaximizeComponent {}
}
} }
background: Kirigami.ShadowedRectangle { background: Kirigami.ShadowedRectangle {
radius: 4 radius: 4

View File

@@ -433,12 +433,6 @@ Kirigami.ScrollablePage {
FileDelegateContextMenu {} FileDelegateContextMenu {}
} }
Component {
id: fullScreenImage
FullScreenImage {}
}
Component { Component {
id: userDetailDialog id: userDetailDialog

View File

@@ -29,7 +29,7 @@
<file alias="PushNotification.qml">qml/RoomSettings/PushNotification.qml</file> <file alias="PushNotification.qml">qml/RoomSettings/PushNotification.qml</file>
<file alias="Categories.qml">qml/RoomSettings/Categories.qml</file> <file alias="Categories.qml">qml/RoomSettings/Categories.qml</file>
<file alias="Permissions.qml">qml/RoomSettings/Permissions.qml</file> <file alias="Permissions.qml">qml/RoomSettings/Permissions.qml</file>
<file alias="FullScreenImage.qml">qml/Component/FullScreenImage.qml</file> <file alias="NeochatMaximizeComponent.qml">qml/Component/NeochatMaximizeComponent.qml</file>
<file alias="FancyEffectsContainer.qml">qml/Component/FancyEffectsContainer.qml</file> <file alias="FancyEffectsContainer.qml">qml/Component/FancyEffectsContainer.qml</file>
<file alias="TypingPane.qml">qml/Component/TypingPane.qml</file> <file alias="TypingPane.qml">qml/Component/TypingPane.qml</file>
<file alias="ShimmerGradient.qml">qml/Component/ShimmerGradient.qml</file> <file alias="ShimmerGradient.qml">qml/Component/ShimmerGradient.qml</file>