summaryrefslogtreecommitdiff
path: root/modules/utilities/cards/RecordingList.qml
diff options
context:
space:
mode:
Diffstat (limited to 'modules/utilities/cards/RecordingList.qml')
-rw-r--r--modules/utilities/cards/RecordingList.qml237
1 files changed, 237 insertions, 0 deletions
diff --git a/modules/utilities/cards/RecordingList.qml b/modules/utilities/cards/RecordingList.qml
new file mode 100644
index 0000000..1250ab3
--- /dev/null
+++ b/modules/utilities/cards/RecordingList.qml
@@ -0,0 +1,237 @@
+pragma ComponentBehavior: Bound
+
+import qs.components
+import qs.components.controls
+import qs.components.containers
+import qs.services
+import qs.config
+import qs.utils
+import Caelestia
+import Caelestia.Models
+import Quickshell
+import Quickshell.Widgets
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ required property var props
+ required property var visibilities
+
+ spacing: 0
+
+ WrapperMouseArea {
+ Layout.fillWidth: true
+
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
+
+ RowLayout {
+ spacing: Appearance.spacing.smaller
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignVCenter
+ text: "list"
+ font.pointSize: Appearance.font.size.large
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ text: qsTr("Recordings")
+ font.pointSize: Appearance.font.size.normal
+ }
+
+ IconButton {
+ icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more"
+ type: IconButton.Text
+ label.animate: true
+ onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
+ }
+ }
+ }
+
+ StyledListView {
+ id: list
+
+ model: FileSystemModel {
+ path: Paths.recsdir
+ nameFilters: ["recording_*.mp4"]
+ sortReverse: true
+ }
+
+ Layout.fillWidth: true
+ Layout.rightMargin: -Appearance.spacing.small
+ implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3)
+ clip: true
+
+ StyledScrollBar.vertical: StyledScrollBar {}
+
+ delegate: RowLayout {
+ id: recording
+
+ required property FileSystemEntry modelData
+ property string baseName
+
+ anchors.left: list.contentItem.left
+ anchors.right: list.contentItem.right
+ anchors.rightMargin: Appearance.spacing.small
+ spacing: Appearance.spacing.small / 2
+
+ Component.onCompleted: baseName = modelData.baseName
+
+ StyledText {
+ Layout.fillWidth: true
+ Layout.rightMargin: Appearance.spacing.small / 2
+ text: {
+ const time = recording.baseName;
+ const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/);
+ if (!matches)
+ return time;
+ const date = new Date(...matches.slice(1));
+ return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale()));
+ }
+ color: Colours.palette.m3onSurfaceVariant
+ elide: Text.ElideRight
+ }
+
+ IconButton {
+ icon: "play_arrow"
+ type: IconButton.Text
+ onClicked: {
+ root.visibilities.utilities = false;
+ Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
+ }
+ }
+
+ IconButton {
+ icon: "folder"
+ type: IconButton.Text
+ onClicked: {
+ root.visibilities.utilities = false;
+ Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
+ }
+ }
+
+ IconButton {
+ icon: "delete_forever"
+ type: IconButton.Text
+ label.color: Colours.palette.m3error
+ stateLayer.color: Colours.palette.m3error
+ onClicked: root.props.recordingConfirmDelete = recording.modelData.path
+ }
+ }
+
+ add: Transition {
+ Anim {
+ property: "opacity"
+ from: 0
+ to: 1
+ }
+ Anim {
+ property: "scale"
+ from: 0.5
+ to: 1
+ }
+ }
+
+ remove: Transition {
+ Anim {
+ property: "opacity"
+ to: 0
+ }
+ Anim {
+ property: "scale"
+ to: 0.5
+ }
+ }
+
+ displaced: Transition {
+ Anim {
+ properties: "opacity,scale"
+ to: 1
+ }
+ Anim {
+ property: "y"
+ }
+ }
+
+ Loader {
+ anchors.centerIn: parent
+
+ opacity: list.count === 0 ? 1 : 0
+ active: opacity > 0
+ asynchronous: true
+
+ sourceComponent: ColumnLayout {
+ spacing: Appearance.spacing.small
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ text: "scan_delete"
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.extraLarge
+
+ opacity: root.props.recordingListExpanded ? 1 : 0
+ scale: root.props.recordingListExpanded ? 1 : 0
+ Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0
+
+ Behavior on opacity {
+ Anim {}
+ }
+
+ Behavior on scale {
+ Anim {}
+ }
+
+ Behavior on Layout.preferredHeight {
+ Anim {}
+ }
+ }
+
+ RowLayout {
+ spacing: Appearance.spacing.smaller
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ text: "scan_delete"
+ color: Colours.palette.m3outline
+
+ opacity: !root.props.recordingListExpanded ? 1 : 0
+ scale: !root.props.recordingListExpanded ? 1 : 0
+ Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0
+
+ Behavior on opacity {
+ Anim {}
+ }
+
+ Behavior on scale {
+ Anim {}
+ }
+
+ Behavior on Layout.preferredWidth {
+ Anim {}
+ }
+ }
+
+ StyledText {
+ text: qsTr("No recordings found")
+ color: Colours.palette.m3outline
+ }
+ }
+ }
+
+ Behavior on opacity {
+ Anim {}
+ }
+ }
+
+ Behavior on implicitHeight {
+ Anim {
+ duration: Appearance.anim.durations.expressiveDefaultSpatial
+ easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
+ }
+ }
+ }
+}