summaryrefslogtreecommitdiff
path: root/components/filedialog/FolderContents.qml
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-08-04 22:45:15 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-08-04 22:45:15 +1000
commitc5381c5194adf97c240acb98eb4c4c950633b325 (patch)
tree52b18eb1771ec6708c86f11d786684f03b8a7c48 /components/filedialog/FolderContents.qml
parentdashboard: display correct temp units (diff)
downloadcaelestia-shell-c5381c5194adf97c240acb98eb4c4c950633b325.tar.gz
caelestia-shell-c5381c5194adf97c240acb98eb4c4c950633b325.tar.bz2
caelestia-shell-c5381c5194adf97c240acb98eb4c4c950633b325.zip
internal: refactor widgets folder
Split into subdirs and rename to components
Diffstat (limited to 'components/filedialog/FolderContents.qml')
-rw-r--r--components/filedialog/FolderContents.qml224
1 files changed, 224 insertions, 0 deletions
diff --git a/components/filedialog/FolderContents.qml b/components/filedialog/FolderContents.qml
new file mode 100644
index 0000000..45930ba
--- /dev/null
+++ b/components/filedialog/FolderContents.qml
@@ -0,0 +1,224 @@
+pragma ComponentBehavior: Bound
+
+import ".."
+import "../controls"
+import "../images"
+import qs.services
+import qs.config
+import qs.utils
+import Quickshell
+import Quickshell.Io
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Effects
+import QtQuick.Controls
+import Qt.labs.folderlistmodel
+
+Item {
+ id: root
+
+ required property var dialog
+ property alias currentItem: view.currentItem
+
+ StyledRect {
+ anchors.fill: parent
+ color: Colours.palette.m3surfaceContainer
+
+ layer.enabled: true
+ layer.effect: MultiEffect {
+ maskSource: mask
+ maskEnabled: true
+ maskInverted: true
+ maskThresholdMin: 0.5
+ maskSpreadAtMin: 1
+ }
+ }
+
+ Item {
+ id: mask
+
+ anchors.fill: parent
+ layer.enabled: true
+ visible: false
+
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.small
+ radius: Appearance.rounding.small
+ }
+ }
+
+ Loader {
+ anchors.centerIn: parent
+ active: view.count === 0
+ asynchronous: true
+ sourceComponent: ColumnLayout {
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ text: "scan_delete"
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.extraLarge * 2
+ font.weight: 500
+ }
+
+ StyledText {
+ text: qsTr("This folder is empty")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.large
+ font.weight: 500
+ }
+ }
+ }
+
+ GridView {
+ id: view
+
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.small + Appearance.padding.normal
+
+ cellWidth: Sizes.itemWidth + Appearance.spacing.small
+ cellHeight: Sizes.itemWidth + Appearance.spacing.small * 2 + Appearance.padding.normal * 2 + 1
+
+ clip: true
+ focus: true
+ currentIndex: -1
+ Keys.onEscapePressed: currentIndex = -1
+
+ Keys.onReturnPressed: {
+ if (root.dialog.selectionValid)
+ root.dialog.accepted(currentItem.filePath);
+ }
+ Keys.onEnterPressed: {
+ if (root.dialog.selectionValid)
+ root.dialog.accepted(currentItem.filePath);
+ }
+
+ ScrollBar.vertical: StyledScrollBar {}
+
+ model: FolderListModel {
+ showDirsFirst: true
+ folder: {
+ let url = "file://";
+ if (root.dialog.cwd[0] === "Home")
+ url += `${Paths.strip(Paths.home)}/${root.dialog.cwd.slice(1).join("/")}`;
+ else
+ url += root.dialog.cwd.join("/");
+ return url;
+ }
+ onFolderChanged: view.currentIndex = -1
+ }
+
+ delegate: StyledRect {
+ id: item
+
+ required property int index
+ required property string fileName
+ required property string filePath
+ required property url fileUrl
+ required property string fileSuffix
+ required property bool fileIsDir
+
+ readonly property real nonAnimHeight: icon.implicitHeight + name.anchors.topMargin + name.implicitHeight + Appearance.padding.normal * 2
+
+ implicitWidth: Sizes.itemWidth
+ implicitHeight: nonAnimHeight
+
+ radius: Appearance.rounding.normal
+ color: GridView.isCurrentItem ? Colours.palette.m3surfaceContainerHighest : "transparent"
+ z: GridView.isCurrentItem || implicitHeight !== nonAnimHeight ? 1 : 0
+ clip: true
+
+ StateLayer {
+ onDoubleClicked: {
+ if (item.fileIsDir)
+ root.dialog.cwd.push(item.fileName);
+ else if (root.dialog.selectionValid)
+ root.dialog.accepted(item.filePath);
+ }
+
+ function onClicked(): void {
+ view.currentIndex = item.index;
+ }
+ }
+
+ CachingIconImage {
+ id: icon
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.topMargin: Appearance.padding.normal
+
+ asynchronous: true
+ implicitSize: Sizes.itemWidth - Appearance.padding.normal * 2
+ source: {
+ if (!item.fileIsDir)
+ return Quickshell.iconPath("application-x-zerosize");
+
+ const name = item.fileName;
+ if (root.dialog.cwd.length === 1 && ["Desktop", "Documents", "Downloads", "Music", "Pictures", "Public", "Templates", "Videos"].includes(name))
+ return Quickshell.iconPath(`folder-${name.toLowerCase()}`);
+
+ return Quickshell.iconPath("inode-directory");
+ }
+
+ onStatusChanged: {
+ if (status === Image.Error)
+ source = Quickshell.iconPath("error");
+ }
+
+ Process {
+ running: !item.fileIsDir
+ command: ["file", "--mime", "-b", item.filePath]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const mime = text.split(";")[0].replace("/", "-");
+ icon.source = Images.validImageTypes.some(t => mime === `image-${t}`) ? item.fileUrl : Quickshell.iconPath(mime, "image-missing");
+ }
+ }
+ }
+ }
+
+ StyledText {
+ id: name
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: icon.bottom
+ anchors.topMargin: Appearance.spacing.small
+ anchors.margins: Appearance.padding.normal
+
+ horizontalAlignment: Text.AlignHCenter
+ text: item.fileName
+ elide: item.GridView.isCurrentItem ? Text.ElideNone : Text.ElideRight
+ wrapMode: item.GridView.isCurrentItem ? Text.WrapAtWordBoundaryOrAnywhere : Text.NoWrap
+ }
+
+ Behavior on implicitHeight {
+ Anim {}
+ }
+ }
+
+ populate: Transition {
+ Anim {
+ property: "scale"
+ from: 0.7
+ to: 1
+ easing.bezierCurve: Appearance.anim.curves.standardDecel
+ }
+ }
+ }
+
+ CurrentItem {
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.margins: Appearance.padding.small
+
+ currentItem: view.currentItem
+ }
+
+ component Anim: NumberAnimation {
+ duration: Appearance.anim.durations.normal
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.anim.curves.standard
+ }
+}