Merge branch 'caelestia-dots:main' into betteractions
This commit is contained in:
commit
5fb727a4c8
9 changed files with 173 additions and 94 deletions
21
.github/CONTRIBUTING.md
vendored
Normal file
21
.github/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Contributing
|
||||
|
||||
There are only a few rules:
|
||||
- Follow the commit convention as follows:
|
||||
- The name of the commit should be `module: change`
|
||||
- Try to be consistent with the module names; you can look at existing commits for the module names I use
|
||||
- If there is more than one change, the change in the commit name should be the most impactful change
|
||||
- Put other changes in the description
|
||||
- Format your code
|
||||
- I use the vscode qml extension with default arguments to format the code, however you do not have to use it
|
||||
- Just try to follow the code style of the rest of the code and ensure that there is:
|
||||
- no trailing whitespace on any lines
|
||||
- a single space between operators
|
||||
- No AI slop allowed
|
||||
- AI readme/docs slop = instant block
|
||||
- PLEASE TEST YOUR PRS
|
||||
- I can't believe I have to put this here, but please test your PRs before submitting them
|
||||
- Your PR must not break anything currently existing, or specify in the description if it does
|
||||
- PR descriptions should be descriptive
|
||||
- Please explain what the PR does and how to use it in your PR description
|
||||
- Also include any breaking changes and/or side effects of the PR
|
||||
|
|
@ -8,6 +8,15 @@ Scope {
|
|||
|
||||
property bool launcherInterrupted
|
||||
|
||||
CustomShortcut {
|
||||
name: "showall"
|
||||
description: "Toggle launcher, dashboard and osd"
|
||||
onPressed: {
|
||||
const v = Visibilities.getForActive();
|
||||
v.launcher = v.dashboard = v.osd = !(v.launcher || v.dashboard || v.osd);
|
||||
}
|
||||
}
|
||||
|
||||
CustomShortcut {
|
||||
name: "session"
|
||||
description: "Toggle session menu"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import QtQuick
|
|||
Item {
|
||||
id: root
|
||||
|
||||
property url source: Wallpapers.current ? `file://${Wallpapers.current}` : ""
|
||||
property string source: Wallpapers.current
|
||||
property Image current: one
|
||||
|
||||
anchors.fill: parent
|
||||
|
|
@ -32,20 +32,14 @@ Item {
|
|||
id: img
|
||||
|
||||
function update(): void {
|
||||
const srcPath = `${root.source}`.slice(7);
|
||||
if (thumbnail.originalPath === srcPath) {
|
||||
if (path === root.source)
|
||||
root.current = this;
|
||||
} else
|
||||
path = srcPath;
|
||||
else
|
||||
path = root.source;
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
loadOriginal: true
|
||||
asynchronous: true
|
||||
cache: false
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
opacity: 0
|
||||
scale: Wallpapers.showPreview ? 1 : 0.8
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ Row {
|
|||
id: root
|
||||
|
||||
padding: Appearance.padding.large
|
||||
spacing: Appearance.spacing.large
|
||||
spacing: Appearance.spacing.normal
|
||||
|
||||
StyledClippingRect {
|
||||
implicitWidth: info.implicitHeight
|
||||
implicitHeight: info.implicitHeight
|
||||
|
||||
radius: Appearance.rounding.full
|
||||
radius: Appearance.rounding.large
|
||||
color: Colours.palette.m3surfaceContainerHigh
|
||||
|
||||
MaterialIcon {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ MouseArea {
|
|||
|
||||
property bool osdHovered
|
||||
property point dragStart
|
||||
property bool dashboardShortcutActive
|
||||
property bool osdShortcutActive
|
||||
|
||||
function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
||||
const panelY = BorderConfig.thickness + panel.y;
|
||||
|
|
@ -37,9 +39,14 @@ MouseArea {
|
|||
onPressed: event => dragStart = Qt.point(event.x, event.y)
|
||||
onContainsMouseChanged: {
|
||||
if (!containsMouse) {
|
||||
visibilities.osd = false;
|
||||
osdHovered = false;
|
||||
visibilities.dashboard = false;
|
||||
// Only hide if not activated by shortcut
|
||||
if (!osdShortcutActive) {
|
||||
visibilities.osd = false;
|
||||
osdHovered = false;
|
||||
}
|
||||
if (!dashboardShortcutActive) {
|
||||
visibilities.dashboard = false;
|
||||
}
|
||||
popouts.hasCurrent = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -47,8 +54,16 @@ MouseArea {
|
|||
onPositionChanged: ({x, y}) => {
|
||||
// Show osd on hover
|
||||
const showOsd = inRightPanel(panels.osd, x, y);
|
||||
visibilities.osd = showOsd;
|
||||
osdHovered = showOsd;
|
||||
|
||||
// Always update visibility based on hover if not in shortcut mode
|
||||
if (!osdShortcutActive) {
|
||||
visibilities.osd = showOsd;
|
||||
osdHovered = showOsd;
|
||||
} else if (showOsd) {
|
||||
// If hovering over OSD area while in shortcut mode, transition to hover control
|
||||
osdShortcutActive = false;
|
||||
osdHovered = true;
|
||||
}
|
||||
|
||||
// Show/hide session on drag
|
||||
if (pressed && withinPanelHeight(panels.session, x, y)) {
|
||||
|
|
@ -60,7 +75,15 @@ MouseArea {
|
|||
}
|
||||
|
||||
// Show dashboard on hover
|
||||
visibilities.dashboard = inTopPanel(panels.dashboard, x, y);
|
||||
const showDashboard = inTopPanel(panels.dashboard, x, y);
|
||||
|
||||
// Always update visibility based on hover if not in shortcut mode
|
||||
if (!dashboardShortcutActive) {
|
||||
visibilities.dashboard = showDashboard;
|
||||
} else if (showDashboard) {
|
||||
// If hovering over dashboard area while in shortcut mode, transition to hover control
|
||||
dashboardShortcutActive = false;
|
||||
}
|
||||
|
||||
// Show popouts on hover
|
||||
const popout = panels.popouts;
|
||||
|
|
@ -75,6 +98,57 @@ MouseArea {
|
|||
popouts.hasCurrent = false;
|
||||
}
|
||||
|
||||
// Monitor individual visibility changes
|
||||
Connections {
|
||||
target: root.visibilities
|
||||
|
||||
function onLauncherChanged() {
|
||||
// If launcher is hidden, clear shortcut flags for dashboard and OSD
|
||||
if (!root.visibilities.launcher) {
|
||||
root.dashboardShortcutActive = false;
|
||||
root.osdShortcutActive = false;
|
||||
|
||||
// Also hide dashboard and OSD if they're not being hovered
|
||||
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
|
||||
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
|
||||
|
||||
if (!inDashboardArea) {
|
||||
root.visibilities.dashboard = false;
|
||||
}
|
||||
if (!inOsdArea) {
|
||||
root.visibilities.osd = false;
|
||||
root.osdHovered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDashboardChanged() {
|
||||
if (root.visibilities.dashboard) {
|
||||
// Dashboard became visible, immediately check if this should be shortcut mode
|
||||
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
|
||||
if (!inDashboardArea) {
|
||||
root.dashboardShortcutActive = true;
|
||||
}
|
||||
} else {
|
||||
// Dashboard hidden, clear shortcut flag
|
||||
root.dashboardShortcutActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onOsdChanged() {
|
||||
if (root.visibilities.osd) {
|
||||
// OSD became visible, immediately check if this should be shortcut mode
|
||||
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
|
||||
if (!inOsdArea) {
|
||||
root.osdShortcutActive = true;
|
||||
}
|
||||
} else {
|
||||
// OSD hidden, clear shortcut flag
|
||||
root.osdShortcutActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Osd.Interactions {
|
||||
screen: root.screen
|
||||
visibilities: root.visibilities
|
||||
|
|
|
|||
3
run.fish
3
run.fish
|
|
@ -4,5 +4,6 @@ set -l dbus 'quickshell.dbus.properties.warning = false;quickshell.dbus.dbusmenu
|
|||
set -l notifs 'quickshell.service.notifications.warning = false' # Notification server warnings on reload
|
||||
set -l sni 'quickshell.service.sni.host.warning = false' # StatusNotifierItem warnings on reload
|
||||
set -l process 'QProcess: Destroyed while process' # Long running processes on reload
|
||||
set -l cache "Cannot open: file://$XDG_CACHE_HOME/caelestia/imagecache/"
|
||||
|
||||
qs -p (dirname (status filename)) --log-rules "$dbus;$notifs;$sni" | grep -vE -e $process
|
||||
qs -p (dirname (status filename)) --log-rules "$dbus;$notifs;$sni" | grep -vF -e $process -e $cache
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import "root:/utils"
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string thumbDir: `${Paths.cache}/thumbnails`.slice(7)
|
||||
|
||||
function go(obj: var): var {
|
||||
return thumbComp.createObject(obj, {
|
||||
originalPath: obj.path,
|
||||
width: obj.width,
|
||||
height: obj.height,
|
||||
loadOriginal: obj.loadOriginal
|
||||
});
|
||||
}
|
||||
|
||||
component Thumbnail: QtObject {
|
||||
id: obj
|
||||
|
||||
required property string originalPath
|
||||
required property int width
|
||||
required property int height
|
||||
required property bool loadOriginal
|
||||
|
||||
property string path
|
||||
|
||||
readonly property Process proc: Process {
|
||||
running: true
|
||||
command: ["fish", "-c", `
|
||||
set -l path "${root.thumbDir}/$(sha1sum ${obj.originalPath} | cut -d ' ' -f 1)@${obj.width}x${obj.height}-exact.png"
|
||||
if test -f $path
|
||||
echo $path
|
||||
else
|
||||
echo 'start'
|
||||
set -l size (identify -ping -format '%w\n%h' ${obj.originalPath})
|
||||
if test $size[1] -gt ${obj.width} -o $size[2] -gt ${obj.height}
|
||||
magick ${obj.originalPath} -${obj.width > 1024 || obj.height > 1024 ? "resize" : "thumbnail"} ${obj.width}x${obj.height}^ -background none -gravity center -extent ${obj.width}x${obj.height} -unsharp 0x.5 $path
|
||||
else
|
||||
cp ${obj.originalPath} $path
|
||||
end
|
||||
echo $path
|
||||
end`]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
if (data === "start") {
|
||||
if (obj.loadOriginal)
|
||||
obj.path = obj.originalPath;
|
||||
} else {
|
||||
obj.path = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reload(): void {
|
||||
proc.signal(9);
|
||||
proc.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: thumbComp
|
||||
|
||||
Thumbnail {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Qt.labs.platform
|
||||
|
||||
Singleton {
|
||||
|
|
@ -12,4 +13,19 @@ Singleton {
|
|||
readonly property url data: `${StandardPaths.standardLocations(StandardPaths.GenericDataLocation)[0]}/caelestia`
|
||||
readonly property url state: `${StandardPaths.standardLocations(StandardPaths.GenericStateLocation)[0]}/caelestia`
|
||||
readonly property url cache: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/caelestia`
|
||||
|
||||
readonly property url imagecache: `${cache}/imagecache`
|
||||
|
||||
function mkdir(path: url): void {
|
||||
mkdirProc.path = path.toString().replace("file://", "");
|
||||
mkdirProc.startDetached();
|
||||
}
|
||||
|
||||
Process {
|
||||
id: mkdirProc
|
||||
|
||||
property string path
|
||||
|
||||
command: ["mkdir", "-p", path]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,50 @@
|
|||
import "root:/services"
|
||||
import "root:/utils"
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Image {
|
||||
id: root
|
||||
|
||||
property string path
|
||||
property bool loadOriginal
|
||||
readonly property Thumbnailer.Thumbnail thumbnail: Thumbnailer.go(this)
|
||||
property string hash
|
||||
readonly property string cachePath: `${Paths.imagecache}/${hash}@${width}x${height}.png`.slice(7)
|
||||
|
||||
source: thumbnail.path ? `file://${thumbnail.path}` : ""
|
||||
asynchronous: true
|
||||
cache: false
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
|
||||
onPathChanged: {
|
||||
shaProc.signal(9);
|
||||
shaProc.path = path.replace("file://", "");
|
||||
shaProc.running = true;
|
||||
}
|
||||
|
||||
onCachePathChanged: {
|
||||
if (hash)
|
||||
source = cachePath;
|
||||
}
|
||||
|
||||
onStatusChanged: {
|
||||
if (source == cachePath && status === Image.Error)
|
||||
source = path;
|
||||
else if (source == path && status === Image.Ready) {
|
||||
Paths.mkdir(Paths.imagecache);
|
||||
const grabPath = cachePath;
|
||||
grabToImage(res => res.saveToFile(grabPath));
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: shaProc
|
||||
|
||||
property string path
|
||||
|
||||
command: ["sha256sum", path]
|
||||
stdout: SplitParser {
|
||||
onRead: data => root.hash = data.split(" ")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue