summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2026-01-10 17:29:29 -0500
committerFreya Murphy <freya@freyacat.org>2026-01-10 17:29:29 -0500
commit3ee6dcd9611986864e78df8dd06cc364e346f4a6 (patch)
treebeb0e2959e66b7f0f5a57d3377b339b8381f6181
parentremove more things, make lock screen use wallpaper not screenshot (diff)
downloadcaelestia-shell-3ee6dcd9611986864e78df8dd06cc364e346f4a6.tar.gz
caelestia-shell-3ee6dcd9611986864e78df8dd06cc364e346f4a6.tar.bz2
caelestia-shell-3ee6dcd9611986864e78df8dd06cc364e346f4a6.zip
remove more things again lol
-rw-r--r--components/filedialog/CurrentItem.qml102
-rw-r--r--components/filedialog/DialogButtons.qml93
-rw-r--r--components/filedialog/FileDialog.qml102
-rw-r--r--components/filedialog/FolderContents.qml229
-rw-r--r--components/filedialog/HeaderBar.qml142
-rw-r--r--components/filedialog/Sidebar.qml113
-rw-r--r--components/filedialog/Sizes.qml8
-rw-r--r--components/images/CachingIconImage.qml42
-rw-r--r--components/images/CachingImage.qml28
-rw-r--r--config/Config.qml1
-rw-r--r--config/UserPaths.qml1
-rw-r--r--modules/dashboard/Content.qml1
-rw-r--r--modules/dashboard/Dash.qml1
-rw-r--r--modules/dashboard/Wrapper.qml1
-rw-r--r--modules/dashboard/dash/User.qml2
-rw-r--r--modules/lock/Center.qml5
-rw-r--r--plugin/src/Caelestia/CMakeLists.txt4
-rw-r--r--plugin/src/Caelestia/Internal/CMakeLists.txt1
-rw-r--r--plugin/src/Caelestia/Internal/cachingimagemanager.cpp223
-rw-r--r--plugin/src/Caelestia/Internal/cachingimagemanager.hpp65
-rw-r--r--plugin/src/Caelestia/Models/CMakeLists.txt8
-rw-r--r--plugin/src/Caelestia/Models/filesystemmodel.cpp479
-rw-r--r--plugin/src/Caelestia/Models/filesystemmodel.hpp148
-rw-r--r--plugin/src/Caelestia/qalculator.cpp52
-rw-r--r--plugin/src/Caelestia/qalculator.hpp19
-rw-r--r--utils/Paths.qml1
26 files changed, 5 insertions, 1866 deletions
diff --git a/components/filedialog/CurrentItem.qml b/components/filedialog/CurrentItem.qml
deleted file mode 100644
index bb87133..0000000
--- a/components/filedialog/CurrentItem.qml
+++ /dev/null
@@ -1,102 +0,0 @@
-import ".."
-import qs.services
-import qs.config
-import QtQuick
-import QtQuick.Shapes
-
-Item {
- id: root
-
- required property var currentItem
-
- implicitWidth: content.implicitWidth + Appearance.padding.larger + content.anchors.rightMargin
- implicitHeight: currentItem ? content.implicitHeight + Appearance.padding.normal + content.anchors.bottomMargin : 0
-
- Shape {
- preferredRendererType: Shape.CurveRenderer
-
- ShapePath {
- id: path
-
- readonly property real rounding: Appearance.rounding.small
- readonly property bool flatten: root.implicitHeight < rounding * 2
- readonly property real roundingY: flatten ? root.implicitHeight / 2 : rounding
-
- strokeWidth: -1
- fillColor: Colours.tPalette.m3surfaceContainer
-
- startX: root.implicitWidth
- startY: root.implicitHeight
-
- PathLine {
- relativeX: -(root.implicitWidth + path.rounding)
- relativeY: 0
- }
- PathArc {
- relativeX: path.rounding
- relativeY: -path.roundingY
- radiusX: path.rounding
- radiusY: Math.min(path.rounding, root.implicitHeight)
- direction: PathArc.Counterclockwise
- }
- PathLine {
- relativeX: 0
- relativeY: -(root.implicitHeight - path.roundingY * 2)
- }
- PathArc {
- relativeX: path.rounding
- relativeY: -path.roundingY
- radiusX: path.rounding
- radiusY: Math.min(path.rounding, root.implicitHeight)
- }
- PathLine {
- relativeX: root.implicitHeight > 0 ? root.implicitWidth - path.rounding * 2 : root.implicitWidth
- relativeY: 0
- }
- PathArc {
- relativeX: path.rounding
- relativeY: -path.rounding
- radiusX: path.rounding
- radiusY: path.rounding
- direction: PathArc.Counterclockwise
- }
-
- Behavior on fillColor {
- CAnim {}
- }
- }
- }
-
- Item {
- anchors.fill: parent
- clip: true
-
- StyledText {
- id: content
-
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.rightMargin: Appearance.padding.larger - Appearance.padding.small
- anchors.bottomMargin: Appearance.padding.normal - Appearance.padding.small
-
- Connections {
- target: root
-
- function onCurrentItemChanged(): void {
- if (root.currentItem)
- content.text = qsTr(`"%1" selected`).arg(root.currentItem.modelData.name);
- }
- }
- }
- }
-
- Behavior on implicitWidth {
- enabled: !!root.currentItem
-
- Anim {}
- }
-
- Behavior on implicitHeight {
- Anim {}
- }
-}
diff --git a/components/filedialog/DialogButtons.qml b/components/filedialog/DialogButtons.qml
deleted file mode 100644
index bde9ac2..0000000
--- a/components/filedialog/DialogButtons.qml
+++ /dev/null
@@ -1,93 +0,0 @@
-import ".."
-import qs.services
-import qs.config
-import QtQuick.Layouts
-
-StyledRect {
- id: root
-
- required property var dialog
- required property FolderContents folder
-
- implicitHeight: inner.implicitHeight + Appearance.padding.normal * 2
-
- color: Colours.tPalette.m3surfaceContainer
-
- RowLayout {
- id: inner
-
- anchors.fill: parent
- anchors.margins: Appearance.padding.normal
-
- spacing: Appearance.spacing.small
-
- StyledText {
- text: qsTr("Filter:")
- }
-
- StyledRect {
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.rightMargin: Appearance.spacing.normal
-
- color: Colours.tPalette.m3surfaceContainerHigh
- radius: Appearance.rounding.small
-
- StyledText {
- anchors.fill: parent
- anchors.margins: Appearance.padding.normal
-
- text: `${root.dialog.filterLabel} (${root.dialog.filters.map(f => `*.${f}`).join(", ")})`
- }
- }
-
- StyledRect {
- color: Colours.tPalette.m3surfaceContainerHigh
- radius: Appearance.rounding.small
-
- implicitWidth: cancelText.implicitWidth + Appearance.padding.normal * 2
- implicitHeight: cancelText.implicitHeight + Appearance.padding.normal * 2
-
- StateLayer {
- disabled: !root.dialog.selectionValid
-
- function onClicked(): void {
- root.dialog.accepted(root.folder.currentItem.modelData.path);
- }
- }
-
- StyledText {
- id: selectText
-
- anchors.centerIn: parent
- anchors.margins: Appearance.padding.normal
-
- text: qsTr("Select")
- color: root.dialog.selectionValid ? Colours.palette.m3onSurface : Colours.palette.m3outline
- }
- }
-
- StyledRect {
- color: Colours.tPalette.m3surfaceContainerHigh
- radius: Appearance.rounding.small
-
- implicitWidth: cancelText.implicitWidth + Appearance.padding.normal * 2
- implicitHeight: cancelText.implicitHeight + Appearance.padding.normal * 2
-
- StateLayer {
- function onClicked(): void {
- root.dialog.rejected();
- }
- }
-
- StyledText {
- id: cancelText
-
- anchors.centerIn: parent
- anchors.margins: Appearance.padding.normal
-
- text: qsTr("Cancel")
- }
- }
- }
-}
diff --git a/components/filedialog/FileDialog.qml b/components/filedialog/FileDialog.qml
deleted file mode 100644
index f3187a5..0000000
--- a/components/filedialog/FileDialog.qml
+++ /dev/null
@@ -1,102 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import qs.components
-import qs.services
-import Quickshell
-import QtQuick
-import QtQuick.Layouts
-
-LazyLoader {
- id: loader
-
- property list<string> cwd: ["Home"]
- property string filterLabel: "All files"
- property list<string> filters: ["*"]
- property string title: qsTr("Select a file")
-
- signal accepted(path: string)
- signal rejected
-
- function open(): void {
- activeAsync = true;
- }
-
- function close(): void {
- rejected();
- }
-
- onAccepted: activeAsync = false
- onRejected: activeAsync = false
-
- FloatingWindow {
- id: root
-
- property list<string> cwd: loader.cwd
- property string filterLabel: loader.filterLabel
- property list<string> filters: loader.filters
-
- readonly property bool selectionValid: {
- const file = folderContents.currentItem?.modelData;
- return (file && !file.isDir && (filters.includes("*") || filters.includes(file.suffix))) ?? false;
- }
-
- function accepted(path: string): void {
- loader.accepted(path);
- }
-
- function rejected(): void {
- loader.rejected();
- }
-
- implicitWidth: 1000
- implicitHeight: 600
- color: Colours.tPalette.m3surface
- title: loader.title
-
- onVisibleChanged: {
- if (!visible)
- rejected();
- }
-
- RowLayout {
- anchors.fill: parent
-
- spacing: 0
-
- Sidebar {
- Layout.fillHeight: true
- dialog: root
- }
-
- ColumnLayout {
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- spacing: 0
-
- HeaderBar {
- Layout.fillWidth: true
- dialog: root
- }
-
- FolderContents {
- id: folderContents
-
- Layout.fillWidth: true
- Layout.fillHeight: true
- dialog: root
- }
-
- DialogButtons {
- Layout.fillWidth: true
- dialog: root
- folder: folderContents
- }
- }
- }
-
- Behavior on color {
- CAnim {}
- }
- }
-}
diff --git a/components/filedialog/FolderContents.qml b/components/filedialog/FolderContents.qml
deleted file mode 100644
index c3b371b..0000000
--- a/components/filedialog/FolderContents.qml
+++ /dev/null
@@ -1,229 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import ".."
-import "../controls"
-import "../images"
-import qs.services
-import qs.config
-import qs.utils
-import Caelestia.Models
-import Quickshell
-import QtQuick
-import QtQuick.Layouts
-import QtQuick.Effects
-
-Item {
- id: root
-
- required property var dialog
- property alias currentItem: view.currentItem
-
- StyledRect {
- anchors.fill: parent
- color: Colours.tPalette.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
-
- opacity: view.count === 0 ? 1 : 0
- active: opacity > 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
- }
- }
-
- Behavior on opacity {
- Anim {}
- }
- }
-
- 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.modelData.path);
- }
- Keys.onEnterPressed: {
- if (root.dialog.selectionValid)
- root.dialog.accepted(currentItem.modelData.path);
- }
-
- StyledScrollBar.vertical: StyledScrollBar {
- flickable: view
- }
-
- model: FileSystemModel {
- path: {
- if (root.dialog.cwd[0] === "Home")
- return `${Paths.home}/${root.dialog.cwd.slice(1).join("/")}`;
- else
- return root.dialog.cwd.join("/");
- }
- onPathChanged: view.currentIndex = -1
- }
-
- delegate: StyledRect {
- id: item
-
- required property int index
- required property FileSystemEntry modelData
-
- 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: Qt.alpha(Colours.tPalette.m3surfaceContainerHighest, GridView.isCurrentItem ? Colours.tPalette.m3surfaceContainerHighest.a : 0)
- z: GridView.isCurrentItem || implicitHeight !== nonAnimHeight ? 1 : 0
- clip: true
-
- StateLayer {
- onDoubleClicked: {
- if (item.modelData.isDir)
- root.dialog.cwd.push(item.modelData.name);
- else if (root.dialog.selectionValid)
- root.dialog.accepted(item.modelData.path);
- }
-
- function onClicked(): void {
- view.currentIndex = item.index;
- }
- }
-
- CachingIconImage {
- id: icon
-
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: parent.top
- anchors.topMargin: Appearance.padding.normal
-
- implicitSize: Sizes.itemWidth - Appearance.padding.normal * 2
-
- Component.onCompleted: {
- const file = item.modelData;
- if (file.isImage)
- source = Qt.resolvedUrl(file.path);
- else if (!file.isDir)
- source = Quickshell.iconPath(file.mimeType.replace("/", "-"), "application-x-zerosize");
- else if (root.dialog.cwd.length === 1 && ["Desktop", "Documents", "Downloads", "Music", "Pictures", "Public", "Templates", "Videos"].includes(file.name))
- source = Quickshell.iconPath(`folder-${file.name.toLowerCase()}`);
- else
- source = Quickshell.iconPath("inode-directory");
- }
- }
-
- 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
- elide: item.GridView.isCurrentItem ? Text.ElideNone : Text.ElideRight
- wrapMode: item.GridView.isCurrentItem ? Text.WrapAtWordBoundaryOrAnywhere : Text.NoWrap
-
- Component.onCompleted: text = item.modelData.name
- }
-
- Behavior on implicitHeight {
- Anim {}
- }
- }
-
- add: Transition {
- Anim {
- properties: "opacity,scale"
- from: 0
- to: 1
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
-
- remove: Transition {
- Anim {
- property: "opacity"
- to: 0
- }
- Anim {
- property: "scale"
- to: 0.5
- }
- }
-
- displaced: Transition {
- Anim {
- properties: "opacity,scale"
- to: 1
- easing.bezierCurve: Appearance.anim.curves.standardDecel
- }
- Anim {
- properties: "x,y"
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
- }
-
- CurrentItem {
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.margins: Appearance.padding.small
-
- currentItem: view.currentItem
- }
-}
diff --git a/components/filedialog/HeaderBar.qml b/components/filedialog/HeaderBar.qml
deleted file mode 100644
index b6e5dba..0000000
--- a/components/filedialog/HeaderBar.qml
+++ /dev/null
@@ -1,142 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import ".."
-import qs.services
-import qs.config
-import QtQuick
-import QtQuick.Layouts
-
-StyledRect {
- id: root
-
- required property var dialog
-
- implicitWidth: inner.implicitWidth + Appearance.padding.normal * 2
- implicitHeight: inner.implicitHeight + Appearance.padding.normal * 2
-
- color: Colours.tPalette.m3surfaceContainer
-
- RowLayout {
- id: inner
-
- anchors.fill: parent
- anchors.margins: Appearance.padding.normal
- spacing: Appearance.spacing.small
-
- Item {
- implicitWidth: implicitHeight
- implicitHeight: upIcon.implicitHeight + Appearance.padding.small * 2
-
- StateLayer {
- radius: Appearance.rounding.small
- disabled: root.dialog.cwd.length === 1
-
- function onClicked(): void {
- root.dialog.cwd.pop();
- }
- }
-
- MaterialIcon {
- id: upIcon
-
- anchors.centerIn: parent
- text: "drive_folder_upload"
- color: root.dialog.cwd.length === 1 ? Colours.palette.m3outline : Colours.palette.m3onSurface
- grade: 200
- }
- }
-
- StyledRect {
- Layout.fillWidth: true
-
- radius: Appearance.rounding.small
- color: Colours.tPalette.m3surfaceContainerHigh
-
- implicitHeight: pathComponents.implicitHeight + pathComponents.anchors.margins * 2
-
- RowLayout {
- id: pathComponents
-
- anchors.fill: parent
- anchors.margins: Appearance.padding.small / 2
- anchors.leftMargin: 0
-
- spacing: Appearance.spacing.small
-
- Repeater {
- model: root.dialog.cwd
-
- RowLayout {
- id: folder
-
- required property string modelData
- required property int index
-
- spacing: 0
-
- Loader {
- Layout.rightMargin: Appearance.spacing.small
- active: folder.index > 0
- asynchronous: true
- sourceComponent: StyledText {
- text: "/"
- color: Colours.palette.m3onSurfaceVariant
- font.bold: true
- }
- }
-
- Item {
- implicitWidth: homeIcon.implicitWidth + (homeIcon.active ? Appearance.padding.small : 0) + folderName.implicitWidth + Appearance.padding.normal * 2
- implicitHeight: folderName.implicitHeight + Appearance.padding.small * 2
-
- Loader {
- anchors.fill: parent
- active: folder.index < root.dialog.cwd.length - 1
- asynchronous: true
- sourceComponent: StateLayer {
- radius: Appearance.rounding.small
-
- function onClicked(): void {
- root.dialog.cwd = root.dialog.cwd.slice(0, folder.index + 1);
- }
- }
- }
-
- Loader {
- id: homeIcon
-
- anchors.left: parent.left
- anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: Appearance.padding.normal
-
- active: folder.index === 0 && folder.modelData === "Home"
- asynchronous: true
- sourceComponent: MaterialIcon {
- text: "home"
- color: root.dialog.cwd.length === 1 ? Colours.palette.m3onSurface : Colours.palette.m3onSurfaceVariant
- fill: 1
- }
- }
-
- StyledText {
- id: folderName
-
- anchors.left: homeIcon.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: homeIcon.active ? Appearance.padding.small : 0
-
- text: folder.modelData
- color: folder.index < root.dialog.cwd.length - 1 ? Colours.palette.m3onSurfaceVariant : Colours.palette.m3onSurface
- font.bold: true
- }
- }
- }
- }
-
- Item {
- Layout.fillWidth: true
- }
- }
- }
- }
-}
diff --git a/components/filedialog/Sidebar.qml b/components/filedialog/Sidebar.qml
deleted file mode 100644
index b55d7b3..0000000
--- a/components/filedialog/Sidebar.qml
+++ /dev/null
@@ -1,113 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import ".."
-import qs.services
-import qs.config
-import QtQuick
-import QtQuick.Layouts
-
-StyledRect {
- id: root
-
- required property var dialog
-
- implicitWidth: Sizes.sidebarWidth
- implicitHeight: inner.implicitHeight + Appearance.padding.normal * 2
-
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: inner
-
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: parent.top
- anchors.margins: Appearance.padding.normal
- spacing: Appearance.spacing.small / 2
-
- StyledText {
- Layout.alignment: Qt.AlignHCenter
- Layout.topMargin: Appearance.padding.small / 2
- Layout.bottomMargin: Appearance.spacing.normal
- text: qsTr("Files")
- color: Colours.palette.m3onSurface
- font.pointSize: Appearance.font.size.larger
- font.bold: true
- }
-
- Repeater {
- model: ["Home", "Downloads", "Desktop", "Documents", "Music", "Pictures", "Videos"]
-
- StyledRect {
- id: place
-
- required property string modelData
- readonly property bool selected: modelData === root.dialog.cwd[root.dialog.cwd.length - 1]
-
- Layout.fillWidth: true
- implicitHeight: placeInner.implicitHeight + Appearance.padding.normal * 2
-
- radius: Appearance.rounding.full
- color: Qt.alpha(Colours.palette.m3secondaryContainer, selected ? 1 : 0)
-
- StateLayer {
- color: place.selected ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
-
- function onClicked(): void {
- if (place.modelData === "Home")
- root.dialog.cwd = ["Home"];
- else
- root.dialog.cwd = ["Home", place.modelData];
- }
- }
-
- RowLayout {
- id: placeInner
-
- anchors.fill: parent
- anchors.margins: Appearance.padding.normal
- anchors.leftMargin: Appearance.padding.large
- anchors.rightMargin: Appearance.padding.large
-
- spacing: Appearance.spacing.normal
-
- MaterialIcon {
- text: {
- const p = place.modelData;
- if (p === "Home")
- return "home";
- if (p === "Downloads")
- return "file_download";
- if (p === "Desktop")
- return "desktop_windows";
- if (p === "Documents")
- return "description";
- if (p === "Music")
- return "music_note";
- if (p === "Pictures")
- return "image";
- if (p === "Videos")
- return "video_library";
- return "folder";
- }
- color: place.selected ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
- font.pointSize: Appearance.font.size.large
- fill: place.selected ? 1 : 0
-
- Behavior on fill {
- Anim {}
- }
- }
-
- StyledText {
- Layout.fillWidth: true
- text: place.modelData
- color: place.selected ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface
- font.pointSize: Appearance.font.size.normal
- elide: Text.ElideRight
- }
- }
- }
- }
- }
-}
diff --git a/components/filedialog/Sizes.qml b/components/filedialog/Sizes.qml
deleted file mode 100644
index 2ad31f9..0000000
--- a/components/filedialog/Sizes.qml
+++ /dev/null
@@ -1,8 +0,0 @@
-pragma Singleton
-
-import Quickshell
-
-Singleton {
- property int itemWidth: 103
- property int sidebarWidth: 200
-}
diff --git a/components/images/CachingIconImage.qml b/components/images/CachingIconImage.qml
deleted file mode 100644
index 1acc6a1..0000000
--- a/components/images/CachingIconImage.qml
+++ /dev/null
@@ -1,42 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import qs.utils
-import Quickshell.Widgets
-import QtQuick
-
-Item {
- id: root
-
- readonly property int status: loader.item?.status ?? Image.Null
- readonly property real actualSize: Math.min(width, height)
- property real implicitSize
- property url source
-
- implicitWidth: implicitSize
- implicitHeight: implicitSize
-
- Loader {
- id: loader
-
- anchors.fill: parent
- sourceComponent: root.source ? root.source.toString().startsWith("image://icon/") ? iconImage : cachingImage : null
- }
-
- Component {
- id: cachingImage
-
- CachingImage {
- path: Paths.toLocalFile(root.source)
- fillMode: Image.PreserveAspectFit
- }
- }
-
- Component {
- id: iconImage
-
- IconImage {
- source: root.source
- asynchronous: true
- }
- }
-}
diff --git a/components/images/CachingImage.qml b/components/images/CachingImage.qml
deleted file mode 100644
index e8f957a..0000000
--- a/components/images/CachingImage.qml
+++ /dev/null
@@ -1,28 +0,0 @@
-import qs.utils
-import Caelestia.Internal
-import Quickshell
-import QtQuick
-
-Image {
- id: root
-
- property alias path: manager.path
-
- asynchronous: true
- fillMode: Image.PreserveAspectCrop
-
- Connections {
- target: QsWindow.window
-
- function onDevicePixelRatioChanged(): void {
- manager.updateSource();
- }
- }
-
- CachingImageManager {
- id: manager
-
- item: root
- cacheDir: Qt.resolvedUrl(Paths.imagecache)
- }
-}
diff --git a/config/Config.qml b/config/Config.qml
index 8927a16..c49240e 100644
--- a/config/Config.qml
+++ b/config/Config.qml
@@ -394,6 +394,7 @@ Singleton {
function serializePaths(): var {
return {
wallpaper: paths.wallpaper,
+ face: paths.face,
sessionGif: paths.sessionGif,
mediaGif: paths.mediaGif
};
diff --git a/config/UserPaths.qml b/config/UserPaths.qml
index 5e35933..f334890 100644
--- a/config/UserPaths.qml
+++ b/config/UserPaths.qml
@@ -3,6 +3,7 @@ import Quickshell.Io
JsonObject {
property string wallpaper: `${Paths.config}/wallpaper.png`
+ property string face: `${Paths.config}/face.png`
property string sessionGif: "root:/assets/len.gif"
property string mediaGif: "root:/assets/bongocat.gif"
}
diff --git a/modules/dashboard/Content.qml b/modules/dashboard/Content.qml
index 70cfaf9..f5f0e46 100644
--- a/modules/dashboard/Content.qml
+++ b/modules/dashboard/Content.qml
@@ -1,7 +1,6 @@
pragma ComponentBehavior: Bound
import qs.components
-import qs.components.filedialog
import qs.config
import Quickshell
import Quickshell.Widgets
diff --git a/modules/dashboard/Dash.qml b/modules/dashboard/Dash.qml
index 0bc81b4..7617ed8 100644
--- a/modules/dashboard/Dash.qml
+++ b/modules/dashboard/Dash.qml
@@ -1,5 +1,4 @@
import qs.components
-import qs.components.filedialog
import qs.services
import qs.config
import "dash"
diff --git a/modules/dashboard/Wrapper.qml b/modules/dashboard/Wrapper.qml
index 3f8f2bd..9758d27 100644
--- a/modules/dashboard/Wrapper.qml
+++ b/modules/dashboard/Wrapper.qml
@@ -1,7 +1,6 @@
pragma ComponentBehavior: Bound
import qs.components
-import qs.components.filedialog
import qs.config
import qs.utils
import Caelestia
diff --git a/modules/dashboard/dash/User.qml b/modules/dashboard/dash/User.qml
index 6cb06f2..0d40873 100644
--- a/modules/dashboard/dash/User.qml
+++ b/modules/dashboard/dash/User.qml
@@ -1,7 +1,5 @@
import qs.components
import qs.components.effects
-import qs.components.images
-import qs.components.filedialog
import qs.services
import qs.config
import qs.utils
diff --git a/modules/lock/Center.qml b/modules/lock/Center.qml
index 748504b..5885252 100644
--- a/modules/lock/Center.qml
+++ b/modules/lock/Center.qml
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import qs.components
import qs.components.controls
-import qs.components.images
import qs.services
import qs.config
import qs.utils
@@ -101,11 +100,11 @@ ColumnLayout {
font.pointSize: Math.floor(root.centerWidth / 4)
}
- CachingImage {
+ Image {
id: pfp
anchors.fill: parent
- path: `${Paths.home}/.face`
+ source: Paths.face ?? ""
}
}
diff --git a/plugin/src/Caelestia/CMakeLists.txt b/plugin/src/Caelestia/CMakeLists.txt
index 18c7315..22d4b97 100644
--- a/plugin/src/Caelestia/CMakeLists.txt
+++ b/plugin/src/Caelestia/CMakeLists.txt
@@ -1,6 +1,5 @@
find_package(Qt6 REQUIRED COMPONENTS Core Qml Gui Quick Concurrent Sql Network DBus)
find_package(PkgConfig REQUIRED)
-pkg_check_modules(Qalculate IMPORTED_TARGET libqalculate REQUIRED)
pkg_check_modules(Pipewire IMPORTED_TARGET libpipewire-0.3 REQUIRED)
pkg_check_modules(Aubio IMPORTED_TARGET aubio REQUIRED)
pkg_check_modules(Cava IMPORTED_TARGET cava REQUIRED)
@@ -41,7 +40,6 @@ qml_module(caelestia
URI Caelestia
SOURCES
cutils.hpp cutils.cpp
- qalculator.hpp qalculator.cpp
appdb.hpp appdb.cpp
requests.hpp requests.cpp
toaster.hpp toaster.cpp
@@ -51,9 +49,7 @@ qml_module(caelestia
Qt::Quick
Qt::Concurrent
Qt::Sql
- PkgConfig::Qalculate
)
add_subdirectory(Internal)
-add_subdirectory(Models)
add_subdirectory(Services)
diff --git a/plugin/src/Caelestia/Internal/CMakeLists.txt b/plugin/src/Caelestia/Internal/CMakeLists.txt
index bdc58db..0240de8 100644
--- a/plugin/src/Caelestia/Internal/CMakeLists.txt
+++ b/plugin/src/Caelestia/Internal/CMakeLists.txt
@@ -1,7 +1,6 @@
qml_module(caelestia-internal
URI Caelestia.Internal
SOURCES
- cachingimagemanager.hpp cachingimagemanager.cpp
circularindicatormanager.hpp circularindicatormanager.cpp
hyprdevices.hpp hyprdevices.cpp
hyprextras.hpp hyprextras.cpp
diff --git a/plugin/src/Caelestia/Internal/cachingimagemanager.cpp b/plugin/src/Caelestia/Internal/cachingimagemanager.cpp
deleted file mode 100644
index 1c15cd2..0000000
--- a/plugin/src/Caelestia/Internal/cachingimagemanager.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-#include "cachingimagemanager.hpp"
-
-#include <QtQuick/qquickwindow.h>
-#include <qcryptographichash.h>
-#include <qdir.h>
-#include <qfileinfo.h>
-#include <qfuturewatcher.h>
-#include <qimagereader.h>
-#include <qpainter.h>
-#include <qtconcurrentrun.h>
-
-namespace caelestia::internal {
-
-qreal CachingImageManager::effectiveScale() const {
- if (m_item && m_item->window()) {
- return m_item->window()->devicePixelRatio();
- }
-
- return 1.0;
-}
-
-QSize CachingImageManager::effectiveSize() const {
- if (!m_item) {
- return QSize();
- }
-
- const qreal scale = effectiveScale();
- const QSize size = QSizeF(m_item->width() * scale, m_item->height() * scale).toSize();
- m_item->setProperty("sourceSize", size);
- return size;
-}
-
-QQuickItem* CachingImageManager::item() const {
- return m_item;
-}
-
-void CachingImageManager::setItem(QQuickItem* item) {
- if (m_item == item) {
- return;
- }
-
- if (m_widthConn) {
- disconnect(m_widthConn);
- }
- if (m_heightConn) {
- disconnect(m_heightConn);
- }
-
- m_item = item;
- emit itemChanged();
-
- if (item) {
- m_widthConn = connect(item, &QQuickItem::widthChanged, this, [this]() {
- updateSource();
- });
- m_heightConn = connect(item, &QQuickItem::heightChanged, this, [this]() {
- updateSource();
- });
- updateSource();
- }
-}
-
-QUrl CachingImageManager::cacheDir() const {
- return m_cacheDir;
-}
-
-void CachingImageManager::setCacheDir(const QUrl& cacheDir) {
- if (m_cacheDir == cacheDir) {
- return;
- }
-
- m_cacheDir = cacheDir;
- if (!m_cacheDir.path().endsWith("/")) {
- m_cacheDir.setPath(m_cacheDir.path() + "/");
- }
- emit cacheDirChanged();
-}
-
-QString CachingImageManager::path() const {
- return m_path;
-}
-
-void CachingImageManager::setPath(const QString& path) {
- if (m_path == path) {
- return;
- }
-
- m_path = path;
- emit pathChanged();
-
- if (!path.isEmpty()) {
- updateSource(path);
- }
-}
-
-void CachingImageManager::updateSource() {
- updateSource(m_path);
-}
-
-void CachingImageManager::updateSource(const QString& path) {
- if (path.isEmpty() || path == m_shaPath) {
- // Path is empty or already calculating sha for path
- return;
- }
-
- m_shaPath = path;
-
- const auto future = QtConcurrent::run(&CachingImageManager::sha256sum, path);
-
- const auto watcher = new QFutureWatcher<QString>(this);
-
- connect(watcher, &QFutureWatcher<QString>::finished, this, [watcher, path, this]() {
- if (m_path != path) {
- // Object is destroyed or path has changed, ignore
- watcher->deleteLater();
- return;
- }
-
- const QSize size = effectiveSize();
-
- if (!m_item || !size.width() || !size.height()) {
- watcher->deleteLater();
- return;
- }
-
- const QString fillMode = m_item->property("fillMode").toString();
- // clang-format off
- const QString filename = QString("%1@%2x%3-%4.png")
- .arg(watcher->result()).arg(size.width()).arg(size.height())
- .arg(fillMode == "PreserveAspectCrop" ? "crop" : fillMode == "PreserveAspectFit" ? "fit" : "stretch");
- // clang-format on
-
- const QUrl cache = m_cacheDir.resolved(QUrl(filename));
- if (m_cachePath == cache) {
- watcher->deleteLater();
- return;
- }
-
- m_cachePath = cache;
- emit cachePathChanged();
-
- if (!cache.isLocalFile()) {
- qWarning() << "CachingImageManager::updateSource: cachePath" << cache << "is not a local file";
- watcher->deleteLater();
- return;
- }
-
- const QImageReader reader(cache.toLocalFile());
- if (reader.canRead()) {
- m_item->setProperty("source", cache);
- } else {
- m_item->setProperty("source", QUrl::fromLocalFile(path));
- createCache(path, cache.toLocalFile(), fillMode, size);
- }
-
- // Clear current running sha if same
- if (m_shaPath == path) {
- m_shaPath = QString();
- }
-
- watcher->deleteLater();
- });
-
- watcher->setFuture(future);
-}
-
-QUrl CachingImageManager::cachePath() const {
- return m_cachePath;
-}
-
-void CachingImageManager::createCache(
- const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const {
- QThreadPool::globalInstance()->start([path, cache, fillMode, size] {
- QImage image(path);
-
- if (image.isNull()) {
- qWarning() << "CachingImageManager::createCache: failed to read" << path;
- return;
- }
-
- image.convertTo(QImage::Format_ARGB32);
-
- if (fillMode == "PreserveAspectCrop") {
- image = image.scaled(size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
- } else if (fillMode == "PreserveAspectFit") {
- image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- } else {
- image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
- }
-
- if (fillMode == "PreserveAspectCrop" || fillMode == "PreserveAspectFit") {
- QImage canvas(size, QImage::Format_ARGB32);
- canvas.fill(Qt::transparent);
-
- QPainter painter(&canvas);
- painter.drawImage((size.width() - image.width()) / 2, (size.height() - image.height()) / 2, image);
- painter.end();
-
- image = canvas;
- }
-
- const QString parent = QFileInfo(cache).absolutePath();
- if (!QDir().mkpath(parent) || !image.save(cache)) {
- qWarning() << "CachingImageManager::createCache: failed to save to" << cache;
- }
- });
-}
-
-QString CachingImageManager::sha256sum(const QString& path) {
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly)) {
- qWarning() << "CachingImageManager::sha256sum: failed to open" << path;
- return "";
- }
-
- QCryptographicHash hash(QCryptographicHash::Sha256);
- hash.addData(&file);
- file.close();
-
- return hash.result().toHex();
-}
-
-} // namespace caelestia::internal
diff --git a/plugin/src/Caelestia/Internal/cachingimagemanager.hpp b/plugin/src/Caelestia/Internal/cachingimagemanager.hpp
deleted file mode 100644
index 3611699..0000000
--- a/plugin/src/Caelestia/Internal/cachingimagemanager.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-#include <QtQuick/qquickitem.h>
-#include <qobject.h>
-#include <qqmlintegration.h>
-
-namespace caelestia::internal {
-
-class CachingImageManager : public QObject {
- Q_OBJECT
- QML_ELEMENT
-
- Q_PROPERTY(QQuickItem* item READ item WRITE setItem NOTIFY itemChanged REQUIRED)
- Q_PROPERTY(QUrl cacheDir READ cacheDir WRITE setCacheDir NOTIFY cacheDirChanged REQUIRED)
-
- Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
- Q_PROPERTY(QUrl cachePath READ cachePath NOTIFY cachePathChanged)
-
-public:
- explicit CachingImageManager(QObject* parent = nullptr)
- : QObject(parent)
- , m_item(nullptr) {}
-
- [[nodiscard]] QQuickItem* item() const;
- void setItem(QQuickItem* item);
-
- [[nodiscard]] QUrl cacheDir() const;
- void setCacheDir(const QUrl& cacheDir);
-
- [[nodiscard]] QString path() const;
- void setPath(const QString& path);
-
- [[nodiscard]] QUrl cachePath() const;
-
- Q_INVOKABLE void updateSource();
- Q_INVOKABLE void updateSource(const QString& path);
-
-signals:
- void itemChanged();
- void cacheDirChanged();
-
- void pathChanged();
- void cachePathChanged();
- void usingCacheChanged();
-
-private:
- QString m_shaPath;
-
- QQuickItem* m_item;
- QUrl m_cacheDir;
-
- QString m_path;
- QUrl m_cachePath;
-
- QMetaObject::Connection m_widthConn;
- QMetaObject::Connection m_heightConn;
-
- [[nodiscard]] qreal effectiveScale() const;
- [[nodiscard]] QSize effectiveSize() const;
-
- void createCache(const QString& path, const QString& cache, const QString& fillMode, const QSize& size) const;
- [[nodiscard]] static QString sha256sum(const QString& path);
-};
-
-} // namespace caelestia::internal
diff --git a/plugin/src/Caelestia/Models/CMakeLists.txt b/plugin/src/Caelestia/Models/CMakeLists.txt
deleted file mode 100644
index 640e29e..0000000
--- a/plugin/src/Caelestia/Models/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-qml_module(caelestia-models
- URI Caelestia.Models
- SOURCES
- filesystemmodel.hpp filesystemmodel.cpp
- LIBRARIES
- Qt::Gui
- Qt::Concurrent
-)
diff --git a/plugin/src/Caelestia/Models/filesystemmodel.cpp b/plugin/src/Caelestia/Models/filesystemmodel.cpp
deleted file mode 100644
index e387ecd..0000000
--- a/plugin/src/Caelestia/Models/filesystemmodel.cpp
+++ /dev/null
@@ -1,479 +0,0 @@
-#include "filesystemmodel.hpp"
-
-#include <qdiriterator.h>
-#include <qfuturewatcher.h>
-#include <qtconcurrentrun.h>
-
-namespace caelestia::models {
-
-FileSystemEntry::FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent)
- : QObject(parent)
- , m_fileInfo(path)
- , m_path(path)
- , m_relativePath(relativePath)
- , m_isImageInitialised(false)
- , m_mimeTypeInitialised(false) {}
-
-QString FileSystemEntry::path() const {
- return m_path;
-};
-
-QString FileSystemEntry::relativePath() const {
- return m_relativePath;
-};
-
-QString FileSystemEntry::name() const {
- return m_fileInfo.fileName();
-};
-
-QString FileSystemEntry::baseName() const {
- return m_fileInfo.baseName();
-};
-
-QString FileSystemEntry::parentDir() const {
- return m_fileInfo.absolutePath();
-};
-
-QString FileSystemEntry::suffix() const {
- return m_fileInfo.completeSuffix();
-};
-
-qint64 FileSystemEntry::size() const {
- return m_fileInfo.size();
-};
-
-bool FileSystemEntry::isDir() const {
- return m_fileInfo.isDir();
-};
-
-bool FileSystemEntry::isImage() const {
- if (!m_isImageInitialised) {
- QImageReader reader(m_path);
- m_isImage = reader.canRead();
- m_isImageInitialised = true;
- }
- return m_isImage;
-}
-
-QString FileSystemEntry::mimeType() const {
- if (!m_mimeTypeInitialised) {
- const QMimeDatabase db;
- m_mimeType = db.mimeTypeForFile(m_path).name();
- m_mimeTypeInitialised = true;
- }
- return m_mimeType;
-}
-
-void FileSystemEntry::updateRelativePath(const QDir& dir) {
- const auto relPath = dir.relativeFilePath(m_path);
- if (m_relativePath != relPath) {
- m_relativePath = relPath;
- emit relativePathChanged();
- }
-}
-
-FileSystemModel::FileSystemModel(QObject* parent)
- : QAbstractListModel(parent)
- , m_recursive(false)
- , m_watchChanges(true)
- , m_showHidden(false)
- , m_filter(NoFilter) {
- connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemModel::watchDirIfRecursive);
- connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemModel::updateEntriesForDir);
-}
-
-int FileSystemModel::rowCount(const QModelIndex& parent) const {
- if (parent != QModelIndex()) {
- return 0;
- }
- return static_cast<int>(m_entries.size());
-}
-
-QVariant FileSystemModel::data(const QModelIndex& index, int role) const {
- if (role != Qt::UserRole || !index.isValid() || index.row() >= m_entries.size()) {
- return QVariant();
- }
- return QVariant::fromValue(m_entries.at(index.row()));
-}
-
-QHash<int, QByteArray> FileSystemModel::roleNames() const {
- return { { Qt::UserRole, "modelData" } };
-}
-
-QString FileSystemModel::path() const {
- return m_path;
-}
-
-void FileSystemModel::setPath(const QString& path) {
- if (m_path == path) {
- return;
- }
-
- m_path = path;
- emit pathChanged();
-
- m_dir.setPath(m_path);
-
- for (const auto& entry : std::as_const(m_entries)) {
- entry->updateRelativePath(m_dir);
- }
-
- update();
-}
-
-bool FileSystemModel::recursive() const {
- return m_recursive;
-}
-
-void FileSystemModel::setRecursive(bool recursive) {
- if (m_recursive == recursive) {
- return;
- }
-
- m_recursive = recursive;
- emit recursiveChanged();
-
- update();
-}
-
-bool FileSystemModel::watchChanges() const {
- return m_watchChanges;
-}
-
-void FileSystemModel::setWatchChanges(bool watchChanges) {
- if (m_watchChanges == watchChanges) {
- return;
- }
-
- m_watchChanges = watchChanges;
- emit watchChangesChanged();
-
- update();
-}
-
-bool FileSystemModel::showHidden() const {
- return m_showHidden;
-}
-
-void FileSystemModel::setShowHidden(bool showHidden) {
- if (m_showHidden == showHidden) {
- return;
- }
-
- m_showHidden = showHidden;
- emit showHiddenChanged();
-
- update();
-}
-
-bool FileSystemModel::sortReverse() const {
- return m_sortReverse;
-}
-
-void FileSystemModel::setSortReverse(bool sortReverse) {
- if (m_sortReverse == sortReverse) {
- return;
- }
-
- m_sortReverse = sortReverse;
- emit sortReverseChanged();
-
- update();
-}
-
-FileSystemModel::Filter FileSystemModel::filter() const {
- return m_filter;
-}
-
-void FileSystemModel::setFilter(Filter filter) {
- if (m_filter == filter) {
- return;
- }
-
- m_filter = filter;
- emit filterChanged();
-
- update();
-}
-
-QStringList FileSystemModel::nameFilters() const {
- return m_nameFilters;
-}
-
-void FileSystemModel::setNameFilters(const QStringList& nameFilters) {
- if (m_nameFilters == nameFilters) {
- return;
- }
-
- m_nameFilters = nameFilters;
- emit nameFiltersChanged();
-
- update();
-}
-
-QQmlListProperty<FileSystemEntry> FileSystemModel::entries() {
- return QQmlListProperty<FileSystemEntry>(this, &m_entries);
-}
-
-void FileSystemModel::watchDirIfRecursive(const QString& path) {
- if (m_recursive && m_watchChanges) {
- const auto currentDir = m_dir;
- const bool showHidden = m_showHidden;
- const auto future = QtConcurrent::run([showHidden, path]() {
- QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot;
- if (showHidden) {
- filters |= QDir::Hidden;
- }
-
- QDirIterator iter(path, filters, QDirIterator::Subdirectories);
- QStringList dirs;
- while (iter.hasNext()) {
- dirs << iter.next();
- }
- return dirs;
- });
- const auto watcher = new QFutureWatcher<QStringList>(this);
- connect(watcher, &QFutureWatcher<QStringList>::finished, this, [currentDir, showHidden, watcher, this]() {
- const auto paths = watcher->result();
- if (currentDir == m_dir && showHidden == m_showHidden && !paths.isEmpty()) {
- // Ignore if dir or showHidden has changed
- m_watcher.addPaths(paths);
- }
- watcher->deleteLater();
- });
- watcher->setFuture(future);
- }
-}
-
-void FileSystemModel::update() {
- updateWatcher();
- updateEntries();
-}
-
-void FileSystemModel::updateWatcher() {
- if (!m_watcher.directories().isEmpty()) {
- m_watcher.removePaths(m_watcher.directories());
- }
-
- if (!m_watchChanges || m_path.isEmpty()) {
- return;
- }
-
- m_watcher.addPath(m_path);
- watchDirIfRecursive(m_path);
-}
-
-void FileSystemModel::updateEntries() {
- if (m_path.isEmpty()) {
- if (!m_entries.isEmpty()) {
- beginResetModel();
- qDeleteAll(m_entries);
- m_entries.clear();
- endResetModel();
- emit entriesChanged();
- }
-
- return;
- }
-
- for (auto& future : m_futures) {
- future.cancel();
- }
- m_futures.clear();
-
- updateEntriesForDir(m_path);
-}
-
-void FileSystemModel::updateEntriesForDir(const QString& dir) {
- const auto recursive = m_recursive;
- const auto showHidden = m_showHidden;
- const auto filter = m_filter;
- const auto nameFilters = m_nameFilters;
-
- QSet<QString> oldPaths;
- for (const auto& entry : std::as_const(m_entries)) {
- oldPaths << entry->path();
- }
-
- const auto future = QtConcurrent::run([=](QPromise<QPair<QSet<QString>, QSet<QString>>>& promise) {
- const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags;
-
- std::optional<QDirIterator> iter;
-
- if (filter == Images) {
- QStringList extraNameFilters = nameFilters;
- const auto formats = QImageReader::supportedImageFormats();
- for (const auto& format : formats) {
- extraNameFilters << "*." + format;
- }
-
- QDir::Filters filters = QDir::Files;
- if (showHidden) {
- filters |= QDir::Hidden;
- }
-
- iter.emplace(dir, extraNameFilters, filters, flags);
- } else {
- QDir::Filters filters;
-
- if (filter == Files) {
- filters = QDir::Files;
- } else if (filter == Dirs) {
- filters = QDir::Dirs | QDir::NoDotAndDotDot;
- } else {
- filters = QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot;
- }
-
- if (showHidden) {
- filters |= QDir::Hidden;
- }
-
- if (nameFilters.isEmpty()) {
- iter.emplace(dir, filters, flags);
- } else {
- iter.emplace(dir, nameFilters, filters, flags);
- }
- }
-
- QSet<QString> newPaths;
- while (iter->hasNext()) {
- if (promise.isCanceled()) {
- return;
- }
-
- QString path = iter->next();
-
- if (filter == Images) {
- QImageReader reader(path);
- if (!reader.canRead()) {
- continue;
- }
- }
-
- newPaths.insert(path);
- }
-
- if (promise.isCanceled() || newPaths == oldPaths) {
- return;
- }
-
- promise.addResult(qMakePair(oldPaths - newPaths, newPaths - oldPaths));
- });
-
- if (m_futures.contains(dir)) {
- m_futures[dir].cancel();
- }
- m_futures.insert(dir, future);
-
- const auto watcher = new QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>(this);
-
- connect(watcher, &QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>::finished, this, [dir, watcher, this]() {
- m_futures.remove(dir);
-
- if (!watcher->future().isResultReadyAt(0)) {
- watcher->deleteLater();
- return;
- }
-
- const auto result = watcher->result();
- applyChanges(result.first, result.second);
-
- watcher->deleteLater();
- });
-
- watcher->setFuture(future);
-}
-
-void FileSystemModel::applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths) {
- QList<int> removedIndices;
- for (int i = 0; i < m_entries.size(); ++i) {
- if (removedPaths.contains(m_entries[i]->path())) {
- removedIndices << i;
- }
- }
- std::sort(removedIndices.begin(), removedIndices.end(), std::greater<int>());
-
- // Batch remove old entries
- int start = -1;
- int end = -1;
- for (int idx : std::as_const(removedIndices)) {
- if (start == -1) {
- start = idx;
- end = idx;
- } else if (idx == end - 1) {
- end = idx;
- } else {
- beginRemoveRows(QModelIndex(), end, start);
- for (int i = start; i >= end; --i) {
- m_entries.takeAt(i)->deleteLater();
- }
- endRemoveRows();
-
- start = idx;
- end = idx;
- }
- }
- if (start != -1) {
- beginRemoveRows(QModelIndex(), end, start);
- for (int i = start; i >= end; --i) {
- m_entries.takeAt(i)->deleteLater();
- }
- endRemoveRows();
- }
-
- // Create new entries
- QList<FileSystemEntry*> newEntries;
- for (const auto& path : addedPaths) {
- newEntries << new FileSystemEntry(path, m_dir.relativeFilePath(path), this);
- }
- std::sort(newEntries.begin(), newEntries.end(), [this](const FileSystemEntry* a, const FileSystemEntry* b) {
- return compareEntries(a, b);
- });
-
- // Batch insert new entries
- int insertStart = -1;
- QList<FileSystemEntry*> batchItems;
- for (const auto& entry : std::as_const(newEntries)) {
- const auto it = std::lower_bound(
- m_entries.begin(), m_entries.end(), entry, [this](const FileSystemEntry* a, const FileSystemEntry* b) {
- return compareEntries(a, b);
- });
- const auto row = static_cast<int>(it - m_entries.begin());
-
- if (insertStart == -1) {
- insertStart = row;
- batchItems << entry;
- } else if (row == insertStart + batchItems.size()) {
- batchItems << entry;
- } else {
- beginInsertRows(QModelIndex(), insertStart, insertStart + static_cast<int>(batchItems.size()) - 1);
- for (int i = 0; i < batchItems.size(); ++i) {
- m_entries.insert(insertStart + i, batchItems[i]);
- }
- endInsertRows();
-
- insertStart = row;
- batchItems.clear();
- batchItems << entry;
- }
- }
- if (!batchItems.isEmpty()) {
- beginInsertRows(QModelIndex(), insertStart, insertStart + static_cast<int>(batchItems.size()) - 1);
- for (int i = 0; i < batchItems.size(); ++i) {
- m_entries.insert(insertStart + i, batchItems[i]);
- }
- endInsertRows();
- }
-
- emit entriesChanged();
-}
-
-bool FileSystemModel::compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) const {
- if (a->isDir() != b->isDir()) {
- return m_sortReverse ^ a->isDir();
- }
- const auto cmp = a->relativePath().localeAwareCompare(b->relativePath());
- return m_sortReverse ? cmp > 0 : cmp < 0;
-}
-
-} // namespace caelestia::models
diff --git a/plugin/src/Caelestia/Models/filesystemmodel.hpp b/plugin/src/Caelestia/Models/filesystemmodel.hpp
deleted file mode 100644
index cf8eae8..0000000
--- a/plugin/src/Caelestia/Models/filesystemmodel.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#pragma once
-
-#include <qabstractitemmodel.h>
-#include <qdir.h>
-#include <qfilesystemwatcher.h>
-#include <qfuture.h>
-#include <qimagereader.h>
-#include <qmimedatabase.h>
-#include <qobject.h>
-#include <qqmlintegration.h>
-#include <qqmllist.h>
-
-namespace caelestia::models {
-
-class FileSystemEntry : public QObject {
- Q_OBJECT
- QML_ELEMENT
- QML_UNCREATABLE("FileSystemEntry instances can only be retrieved from a FileSystemModel")
-
- Q_PROPERTY(QString path READ path CONSTANT)
- Q_PROPERTY(QString relativePath READ relativePath NOTIFY relativePathChanged)
- Q_PROPERTY(QString name READ name CONSTANT)
- Q_PROPERTY(QString baseName READ baseName CONSTANT)
- Q_PROPERTY(QString parentDir READ parentDir CONSTANT)
- Q_PROPERTY(QString suffix READ suffix CONSTANT)
- Q_PROPERTY(qint64 size READ size CONSTANT)
- Q_PROPERTY(bool isDir READ isDir CONSTANT)
- Q_PROPERTY(bool isImage READ isImage CONSTANT)
- Q_PROPERTY(QString mimeType READ mimeType CONSTANT)
-
-public:
- explicit FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent = nullptr);
-
- [[nodiscard]] QString path() const;
- [[nodiscard]] QString relativePath() const;
- [[nodiscard]] QString name() const;
- [[nodiscard]] QString baseName() const;
- [[nodiscard]] QString parentDir() const;
- [[nodiscard]] QString suffix() const;
- [[nodiscard]] qint64 size() const;
- [[nodiscard]] bool isDir() const;
- [[nodiscard]] bool isImage() const;
- [[nodiscard]] QString mimeType() const;
-
- void updateRelativePath(const QDir& dir);
-
-signals:
- void relativePathChanged();
-
-private:
- const QFileInfo m_fileInfo;
-
- const QString m_path;
- QString m_relativePath;
-
- mutable bool m_isImage;
- mutable bool m_isImageInitialised;
-
- mutable QString m_mimeType;
- mutable bool m_mimeTypeInitialised;
-};
-
-class FileSystemModel : public QAbstractListModel {
- Q_OBJECT
- QML_ELEMENT
-
- Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
- Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
- Q_PROPERTY(bool watchChanges READ watchChanges WRITE setWatchChanges NOTIFY watchChangesChanged)
- Q_PROPERTY(bool showHidden READ showHidden WRITE setShowHidden NOTIFY showHiddenChanged)
- Q_PROPERTY(bool sortReverse READ sortReverse WRITE setSortReverse NOTIFY sortReverseChanged)
- Q_PROPERTY(Filter filter READ filter WRITE setFilter NOTIFY filterChanged)
- Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
-
- Q_PROPERTY(QQmlListProperty<caelestia::models::FileSystemEntry> entries READ entries NOTIFY entriesChanged)
-
-public:
- enum Filter {
- NoFilter,
- Images,
- Files,
- Dirs
- };
- Q_ENUM(Filter)
-
- explicit FileSystemModel(QObject* parent = nullptr);
-
- int rowCount(const QModelIndex& parent = QModelIndex()) const override;
- QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
- QHash<int, QByteArray> roleNames() const override;
-
- [[nodiscard]] QString path() const;
- void setPath(const QString& path);
-
- [[nodiscard]] bool recursive() const;
- void setRecursive(bool recursive);
-
- [[nodiscard]] bool watchChanges() const;
- void setWatchChanges(bool watchChanges);
-
- [[nodiscard]] bool showHidden() const;
- void setShowHidden(bool showHidden);
-
- [[nodiscard]] bool sortReverse() const;
- void setSortReverse(bool sortReverse);
-
- [[nodiscard]] Filter filter() const;
- void setFilter(Filter filter);
-
- [[nodiscard]] QStringList nameFilters() const;
- void setNameFilters(const QStringList& nameFilters);
-
- [[nodiscard]] QQmlListProperty<FileSystemEntry> entries();
-
-signals:
- void pathChanged();
- void recursiveChanged();
- void watchChangesChanged();
- void showHiddenChanged();
- void sortReverseChanged();
- void filterChanged();
- void nameFiltersChanged();
- void entriesChanged();
-
-private:
- QDir m_dir;
- QFileSystemWatcher m_watcher;
- QList<FileSystemEntry*> m_entries;
- QHash<QString, QFuture<QPair<QSet<QString>, QSet<QString>>>> m_futures;
-
- QString m_path;
- bool m_recursive;
- bool m_watchChanges;
- bool m_showHidden;
- bool m_sortReverse;
- Filter m_filter;
- QStringList m_nameFilters;
-
- void watchDirIfRecursive(const QString& path);
- void update();
- void updateWatcher();
- void updateEntries();
- void updateEntriesForDir(const QString& dir);
- void applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths);
- [[nodiscard]] bool compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) const;
-};
-
-} // namespace caelestia::models
diff --git a/plugin/src/Caelestia/qalculator.cpp b/plugin/src/Caelestia/qalculator.cpp
deleted file mode 100644
index 44e8d21..0000000
--- a/plugin/src/Caelestia/qalculator.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "qalculator.hpp"
-
-#include <libqalculate/qalculate.h>
-
-namespace caelestia {
-
-Qalculator::Qalculator(QObject* parent)
- : QObject(parent) {
- if (!CALCULATOR) {
- new Calculator();
- CALCULATOR->loadExchangeRates();
- CALCULATOR->loadGlobalDefinitions();
- CALCULATOR->loadLocalDefinitions();
- }
-}
-
-QString Qalculator::eval(const QString& expr, bool printExpr) const {
- if (expr.isEmpty()) {
- return QString();
- }
-
- EvaluationOptions eo;
- PrintOptions po;
-
- std::string parsed;
- std::string result = CALCULATOR->calculateAndPrint(
- CALCULATOR->unlocalizeExpression(expr.toStdString(), eo.parse_options), 100, eo, po, &parsed);
-
- std::string error;
- while (CALCULATOR->message()) {
- if (!CALCULATOR->message()->message().empty()) {
- if (CALCULATOR->message()->type() == MESSAGE_ERROR) {
- error += "error: ";
- } else if (CALCULATOR->message()->type() == MESSAGE_WARNING) {
- error += "warning: ";
- }
- error += CALCULATOR->message()->message();
- }
- CALCULATOR->nextMessage();
- }
- if (!error.empty()) {
- return QString::fromStdString(error);
- }
-
- if (printExpr) {
- return QString("%1 = %2").arg(parsed).arg(result);
- }
-
- return QString::fromStdString(result);
-}
-
-} // namespace caelestia
diff --git a/plugin/src/Caelestia/qalculator.hpp b/plugin/src/Caelestia/qalculator.hpp
deleted file mode 100644
index a07a8a2..0000000
--- a/plugin/src/Caelestia/qalculator.hpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-
-#include <qobject.h>
-#include <qqmlintegration.h>
-
-namespace caelestia {
-
-class Qalculator : public QObject {
- Q_OBJECT
- QML_ELEMENT
- QML_SINGLETON
-
-public:
- explicit Qalculator(QObject* parent = nullptr);
-
- Q_INVOKABLE QString eval(const QString& expr, bool printExpr = true) const;
-};
-
-} // namespace caelestia
diff --git a/utils/Paths.qml b/utils/Paths.qml
index c8f74d7..3b7e84f 100644
--- a/utils/Paths.qml
+++ b/utils/Paths.qml
@@ -19,6 +19,7 @@ Singleton {
readonly property string imagecache: `${cache}/imagecache`
readonly property string notifimagecache: `${imagecache}/notifs`
readonly property string wallpaper: Quickshell.env("CAELESTIA_WALLPAPER") || absolutePath(Config.paths.wallpaper)
+ readonly property string face: Quickshell.env("CAELESTIA_FACE") || absolutePath(Config.paths.face)
readonly property string libdir: Quickshell.env("CAELESTIA_LIB_DIR") || "/usr/lib/caelestia"
function toLocalFile(path: url): string {