1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-02 10:32:07 -04:00

Compare commits

..

120 Commits

Author SHA1 Message Date
bbedward
3f24cf37ca settings: make horizontal change more smart 2026-02-24 20:49:02 -05:00
bbedward
01218f34cb settings: restore notifyHorizontalBarChanged 2026-02-24 19:43:01 -05:00
purian23
9da58d8296 fix: Update HTML rendering injections 2026-02-24 19:43:01 -05:00
purian23
af0038e634 dbar: Refactor to memoize dbar & widget state via json 2026-02-24 19:20:30 -05:00
purian23
05c312b9eb cpu widget: Fix monitor binding 2026-02-24 19:20:30 -05:00
bbedward
89d5c958c4 settings: use Image in theme colors tab wp preview 2026-02-24 15:23:07 -05:00
bbedward
e4d86ad595 popout: fully unload popout layers on close 2026-02-24 15:20:00 -05:00
bbedward
532b54a028 wallpaper: handle initial load better, add dms randr command for quick physical scale retrieval 2026-02-24 15:20:00 -05:00
bbedward
504d027c3f privacy indicator: fix width when not active 2026-02-24 13:59:58 -05:00
bbedward
e8f95f4533 settings: use Image for per-mode previews 2026-02-24 13:37:34 -05:00
bbedward
b83256c83a matugen: skip theme refreshes if no colors changed 2026-02-24 13:37:34 -05:00
bbedward
8e2cd21be8 dock: fix tooltip positioning 2026-02-24 13:37:34 -05:00
bbedward
c5413608da dankbar: fix some defaults in reset 2026-02-24 13:37:34 -05:00
bbedward
586bcad442 widgets: set updatesEnabled false on background layers, if qs supports it 2026-02-24 13:37:34 -05:00
bbedward
3b3d10f730 widgets: fix moddedAppID consistency 2026-02-24 13:37:34 -05:00
purian23
4834891b36 settings: Re-adjust dbar layout 2026-02-24 13:37:34 -05:00
purian23
f60e65aecb settings: Dankbar layout updates 2026-02-24 13:37:34 -05:00
purian23
01387b0123 fix: Clipboard button widget alignment 2026-02-24 13:37:34 -05:00
bbedward
1476658c23 dankbar: fix syncing settings to new bars 2026-02-24 13:37:34 -05:00
bbedward
7861c6e316 i18n: term sync 2026-02-24 10:52:35 -05:00
bbedward
d2247d7b24 dankbar: restore horizontal change debounce 2026-02-24 10:52:35 -05:00
bbedward
2ff78d4a02 dpms: disable fade overlay in onRequestMonitorOn 2026-02-24 10:52:35 -05:00
bbedward
785243ce5f dankbar: optimize bindings in bar window 2026-02-24 10:52:35 -05:00
bbedward
0e1b868384 widgets: fix undefined icon warnings 2026-02-24 10:52:35 -05:00
null
2b08e800e8 feat: improve icon resolution and align switcher fallback styling (#1823)
- Implement deep search icon resolution in DesktopService with runtime caching.
- Update Paths.getAppIcon to utilize enhanced resolution for mismatched app IDs.
- Align Workspace Switcher fallback icons with AppsDock visual style.
- Synchronize fallback text logic between Switcher and Dock using app names.
2026-02-24 10:52:35 -05:00
purian23
74e4f8ea1e display: Fix output config on delete & popup height 2026-02-24 10:52:35 -05:00
purian23
9c58569b4c template: Refine bug report tracker 2026-02-24 10:52:35 -05:00
purian23
29de677e00 feat: Refactor DankBar w/New granular options - New background toggles - New maxIcon & maxText widget sizes (global) - Dedicated M3 padding slider - New independent icon scale options - Updated logic to improve performance on single & dual bar modes 2026-02-24 10:52:35 -05:00
purian23
fae4944845 fix: Animated Image warnings 2026-02-24 10:52:34 -05:00
Lucas
07a0ac4b7d doctor: fix imageformats detection (#1811) 2026-02-23 19:45:10 -05:00
bbedward
b2d8f4d73b keybinds: preserve scroll position of expanded item on list change fixes #1766 2026-02-23 19:33:29 -05:00
bbedward
fe58c45233 widgets: fallback when AnimatedImage probe fails to static Image 2026-02-23 19:03:48 -05:00
bbedward
3ea4e389eb thememode: connect to loginctl PrepareForSleep event 2026-02-23 19:03:48 -05:00
purian23
7276f295fc dms-greeter: Update dankinstall greeter automation w/distro packages 2026-02-23 18:53:29 -05:00
bbedward
93ed96a789 launcher: don't tie unload to visibility 2026-02-23 18:53:29 -05:00
purian23
bea325e94c audio: Sync audio hide opts w/dash Output devices 2026-02-23 18:53:29 -05:00
bbedward
2f8f1c30ad audio: fix cycle output, improve icon resolution for sink fixes #1808 2026-02-23 18:53:29 -05:00
Lucas
f859a14173 nix: update flake.lock (#1809) 2026-02-23 18:53:29 -05:00
bbedward
153f39da48 audio: disable effects when mpris player is playing 2026-02-23 18:53:29 -05:00
bbedward
e4accdd1c7 launcher: implement memory for selected tab fixes #1806 2026-02-23 10:20:48 -05:00
dms-ci[bot]
a2c89e0a8c nix: update vendorHash for go.mod changes 2026-02-23 10:20:48 -05:00
bbedward
e282831c2e widgets: make AnimatedImage conditional in DankCircularImage - Cut potential overhead of always using AnimatedImage 2026-02-23 10:20:48 -05:00
bbedward
5c5ff6195a osd: disable media playback OSD by default 2026-02-23 10:20:48 -05:00
Triệu Kha
c4bbf54679 clipboard: fix html elements get parsed in clipboard entry (#1798)
* clipboard: fix html elements get parsed in clipboard entry

* Revert "clipboard: fix html elements get parsed in clipboard entry"

This reverts commit 52b11eeb98.

* clipboard: fix html elements get parsed in clipboard entry
2026-02-23 10:20:48 -05:00
Jonas Bloch
98acafb4b8 fix(notepad): decode path URI when saving/creating a file (#1805) 2026-02-23 10:20:48 -05:00
Jonas Bloch
da20681fc0 feat: add support for animated gifs as profile pictures (#1804) 2026-02-23 10:20:48 -05:00
purian23
b38cb961b2 dms-greeter: Enable greetd via dms greeter install all-in-one cmd 2026-02-23 10:20:48 -05:00
bbedward
7a0bb07518 matugen: unconditionally run portal sync even if matugen errors 2026-02-22 23:09:18 -05:00
purian23
403e3e90a2 dms-greeter: Enhance DMS Greeter dankinstall & packaging across distros - Added support for Debian, Ubuntu, Fedora, Arch, and OpenSUSE on dankinstall / dms greeter install 2026-02-22 23:09:18 -05:00
bbedward
50b91f14b6 launcher: fix frecency ranking in search results fixes #1799 2026-02-22 23:09:18 -05:00
bbedward
b3df47fce0 scripts: fix shellcheck 2026-02-22 23:09:18 -05:00
bbedward
09bd65d746 bluetooth: expose trust/untrust on devices 2026-02-22 23:09:18 -05:00
长夜月玩Fedora
020d56ab7f Add support for 'evernight' distribution in Fedora (#1786) 2026-02-22 23:09:18 -05:00
Triệu Kha
f3bee65da9 Fix dock visible when theres no app (#1797)
* clipboard: improve image thumbnail
- thumbnail image is now bigger
- circular mask has been replaced with rounded rectangular mask

* dock: fix dock still visible when there's no app
2026-02-22 23:09:18 -05:00
purian23
b14b0946e2 feat: DMS Greeter packaging for Debian/OpenSUSE on OBS 2026-02-22 23:09:18 -05:00
Lucas
ca44205f1c zen: add more commands to detection (#1792) 2026-02-22 23:09:18 -05:00
purian23
2d39e8fd2a ipc: Fix DankDash Wallpaper call 2026-02-22 23:09:18 -05:00
purian23
6d4df6e927 theme: Fix Light/Dark mode portal sync 2026-02-22 23:09:18 -05:00
Connor Welsh
b8ab86e6c0 distro: add cups-pk-helper as suggested dependency (#1670) 2026-02-22 23:09:18 -05:00
bbedward
837329a6d8 window rules: default to fixed for width/height part of #1774 2026-02-22 23:09:18 -05:00
purian23
8c6c2ffd23 ubuntu: Fix dms-git Go versioning to restore builds 2026-02-22 23:09:18 -05:00
bbedward
ad3c8b6755 v1.4.3 version file 2026-02-22 23:07:18 -05:00
bbedward
03a8e1e0d5 clipboard: fix memory leak from unbounded offer maps and unguarded file reads 2026-02-20 11:42:14 -05:00
bbedward
4d4d3c20a1 keybinds/niri: fix quote preservation 2026-02-20 11:42:14 -05:00
bbedward
cef16d6bc9 dankdash: fix widgets across different bar section fixes #1764s 2026-02-20 11:42:14 -05:00
bbedward
aafaad1791 core/screenshot: light cleanups 2026-02-20 11:42:14 -05:00
Patrick Fischer
7906fdc2b0 screensaver: emit ActiveChanged on lock/unlock (#1761) 2026-02-20 11:42:14 -05:00
Triệu Kha
397650ca52 clipboard: improve image thumbnail (#1759)
- thumbnail image is now bigger
- circular mask has been replaced with rounded rectangular mask
2026-02-20 11:42:14 -05:00
purian23
826207006a template: Default install method 2026-02-20 11:42:14 -05:00
purian23
58c2fcd31c issues: Template fix 2026-02-20 11:42:14 -05:00
purian23
b2a2b425ec templates: Fix GitHub issue labels 2026-02-20 11:42:14 -05:00
shorinkiwata
942c9c9609 feat(distros): allow CatOS to run DMS installer (#1768)
- This PR adds support for **CatOS**
- CatOS is fully compatible with Arch Linux
2026-02-20 11:42:14 -05:00
purian23
46d6e1cff3 templates: Update DMS issue formats 2026-02-20 11:42:14 -05:00
bbedward
a4137c57c1 running apps: fix ordering on niri 2026-02-19 20:46:26 -05:00
bbedward
1ad8b627f1 launcher: fix premature exit of file search fixes #1749 2026-02-19 16:47:34 -05:00
Jonas Bloch
58a02ce290 Search keybinds fixes (#1748)
* fix: close keybind cheatsheet on escape press

* feat: match all space separated words in keybind cheatsheet search
2026-02-19 16:27:14 -05:00
bbedward
8e1ad1a2be audio: fix hide device not working 2026-02-19 16:24:48 -05:00
bbedward
68cd7ab32c i18n: term sync 2026-02-19 14:11:21 -05:00
Youseffo13
f649ce9a8e Added missing i18n strings and changed reset button (#1746)
* Update it.json

* Enhance SettingsSliderRow: add resetText property and update reset button styling

* added i18n strings

* adjust reset button width to be dynamic based on content size

* added i18n strings

* Update template.json

* reverted changes

* Update it.json

* Update template.json
2026-02-19 14:11:21 -05:00
bbedward
c4df242f07 dankbar: remove behaviors from monitoring widgets 2026-02-19 14:11:21 -05:00
bbedward
26846c8d55 dgop: round computed values to match display format 2026-02-19 14:11:21 -05:00
bbedward
31b44a667c flake: fix dev flake for go 1.25 and ashellchheck 2026-02-19 14:11:21 -05:00
bbedward
4f3b73ee21 hyprland: add serial to output model generator 2026-02-19 09:22:56 -05:00
bbedward
4cfae91f02 dock: fix context menu styling fixes #1742 2026-02-19 09:22:56 -05:00
bbedward
8d947a6e95 dock: fix transparency setting fixes #1739 2026-02-19 09:22:56 -05:00
bbedward
1e84d4252c launcher: improve perf of settings search 2026-02-19 09:22:56 -05:00
bbedward
76072e1d4c launcher: always heuristic lookup cached entries 2026-02-19 09:22:56 -05:00
bbedward
6408dce4a9 launcher v2: always heuristicLookup tab actions 2026-02-18 19:07:30 -05:00
bbedward
0b2e1cca38 i18n: term updates 2026-02-18 18:35:29 -05:00
bbedward
c1bfd8c0b7 system tray: fix to take up 0 space when empty 2026-02-18 18:35:29 -05:00
Youseffo13
90ffa5833b Added Missing i18n strings (#1729)
* inverted dock visibility and position option

* added missing I18n strings

* added missing i18n strings

* added i18n strings

* Added missing i18n strings

* updated translations

* Update it.json
2026-02-18 18:35:29 -05:00
bbedward
169c669286 widgets: add openWith/toggleWith modes for dankbar widgets 2026-02-18 16:24:07 -05:00
bbedward
f8350deafc keybinds: fix escape in keybinds modal 2026-02-18 14:57:53 -05:00
bbedward
0286a1b80b launcher v2: remove calc cc: enhancements for plugins to size details 2026-02-18 14:48:44 -05:00
beluch-dev
7c3e6c1f02 fix: correct parameter name in Hyprland windowrule (no_initial_focus) (#1726)
##Description
This PR corrects the parameter name to match new Hyprland standard.

## Changes
-Before: 'noinitialfocus'
-After: 'no_initial_focus'
2026-02-18 14:48:40 -05:00
bbedward
d2d72db3c9 plugins: fix settings focus loss 2026-02-18 13:36:51 -05:00
Evgeny Zemtsov
f81f861408 handle recycled server object IDs for workspace/group handles (#1725)
When switching tabs rapidly or closing multiple tabs, the taskbar shows
"ghost" workspaces — entries with no name, no coordinates, and no active
state. The ghosts appear at positions where workspaces were removed and
then recreated by the compositor.

When a compositor removes a workspace (sends `removed` event) and the
client calls Destroy(), the proxy is marked as zombie but stays in the
Context.objects map. For server-created objects (IDs >= 0xFF000000), the
server never sends `delete_id`, so the zombie proxy persists indefinitely.

When the compositor later creates a new workspace that gets a recycled
server object ID, GetProxy() returns the old zombie proxy. The dispatch
loop in GetDispatch() checks IsZombie() and silently drops ALL events
for zombie proxies — including property events (name, id, coordinates,
state, capabilities) intended for the new workspace. This causes the
ghost workspaces with empty properties in the UI.

Fix: check IsZombie() when handling `workspace` and `workspace_group`
events that carry a `new_id` argument. If the existing proxy is a
zombie, treat it as absent and create a fresh proxy via
registerServerProxy(), which replaces the zombie in the map. Subsequent
property events are then dispatched to the live proxy.
2026-02-18 13:36:51 -05:00
bbedward
af494543f5 1.4.2: staging ground 2026-02-18 13:36:43 -05:00
bbedward
db4de55338 popout: decouple shadow from content layer 2026-02-18 10:46:01 -05:00
bbedward
37ecbbbbde popout: disable layer after animation 2026-02-18 10:34:21 -05:00
purian23
d6a6d2a438 notifications: Maintain shadow during expansion 2026-02-18 10:34:21 -05:00
purian23
bf1c6eec74 notifications: Update initial popup height surfaces 2026-02-18 10:34:21 -05:00
bbedward
0ddae80584 running apps: fix scroll events being propagated fixes #1724 2026-02-18 10:34:21 -05:00
bbedward
5c96c03bfa matugen: make v4 detection more resilient 2026-02-18 09:57:35 -05:00
bbedward
dfe36e47d8 process list: fix scaling with fonts fixes #1721 2026-02-18 09:57:35 -05:00
purian23
63e1b75e57 dankinstall: Fix Debian ARM64 detection 2026-02-18 09:57:35 -05:00
bbedward
29efdd8598 matugen: detect emacs directory fixes #1720 2026-02-18 09:57:35 -05:00
bbedward
34d03cf11b osd: optimize bindings 2026-02-18 09:57:35 -05:00
bbedward
c339389d44 screenshot: adjust cursor CLI option to be more explicit 2026-02-17 22:28:46 -05:00
bbedward
af5f6eb656 settings: workaround crash 2026-02-17 22:20:19 -05:00
purian23
a6d28e2553 notifications: Tweak animation scale & settings 2026-02-17 22:07:36 -05:00
bbedward
6213267908 settings: guard internal writes from watcher 2026-02-17 22:03:57 -05:00
bbedward
d084114149 cc: fix plugin reloading in bar position changes 2026-02-17 17:25:19 -05:00
bbedward
f6d99eca0d popout: anchor height changing popout surfaces to top and bottom 2026-02-17 17:25:19 -05:00
bbedward
722eb3289e workspaces: fix named workspace icons 2026-02-17 17:25:19 -05:00
bbedward
b7f2bdcb2d dankinstall: no_anim on dms layers 2026-02-17 17:25:19 -05:00
bbedward
11c20db6e6 1.4.1 2026-02-17 14:08:15 -05:00
bbedward
8a4e3f8bb1 system updater: fix hide no update option 2026-02-17 14:08:04 -05:00
bbedward
bc8fe97c13 launcher: fix kb navigation not always showing last delegate in view 2026-02-17 14:08:04 -05:00
bbedward
47262155aa doctor: add qt6-imageformats check 2026-02-17 14:08:04 -05:00
83 changed files with 920 additions and 3125 deletions

View File

@@ -9,8 +9,8 @@ on:
type: choice
options:
- dms
- dms-greeter
- dms-git
- dms-greeter
- all
default: "dms"
rebuild_release:
@@ -119,8 +119,9 @@ jobs:
echo "🔄 Manual rebuild requested: $PKG (db$REBUILD)"
elif [[ "$PKG" == "all" ]]; then
# Check each stable package and build list of those needing updates
# Check each package and build list of those needing updates
PACKAGES_TO_UPDATE=()
check_dms_git && PACKAGES_TO_UPDATE+=("dms-git")
if check_dms_stable; then
PACKAGES_TO_UPDATE+=("dms")
if [[ -n "$LATEST_TAG" ]]; then
@@ -139,7 +140,7 @@ jobs:
else
echo "packages=" >> $GITHUB_OUTPUT
echo "has_updates=false" >> $GITHUB_OUTPUT
echo "✓ Both packages up to date"
echo "✓ All packages up to date"
fi
elif [[ "$PKG" == "dms-git" ]]; then
@@ -244,7 +245,7 @@ jobs:
fi
- name: Update dms-git spec version
if: contains(steps.packages.outputs.packages, 'dms-git')
if: contains(steps.packages.outputs.packages, 'dms-git') || steps.packages.outputs.packages == 'all'
run: |
COMMIT_HASH=$(git rev-parse --short=8 HEAD)
COMMIT_COUNT=$(git rev-list --count HEAD)
@@ -265,7 +266,7 @@ jobs:
} > distro/opensuse/dms-git.spec
- name: Update Debian dms-git changelog version
if: contains(steps.packages.outputs.packages, 'dms-git')
if: contains(steps.packages.outputs.packages, 'dms-git') || steps.packages.outputs.packages == 'all'
run: |
COMMIT_HASH=$(git rev-parse --short=8 HEAD)
COMMIT_COUNT=$(git rev-list --count HEAD)
@@ -388,7 +389,7 @@ jobs:
UPLOADED_PACKAGES=()
SKIPPED_PACKAGES=()
# PACKAGES can be space-separated list (e.g., "dms dms-greeter" from "all" check)
# PACKAGES can be space-separated list (e.g., "dms-git dms" from "all" check)
# Loop through each package and upload
for PKG in $PACKAGES; do
echo ""

View File

@@ -4,15 +4,9 @@ on:
workflow_dispatch:
inputs:
package:
description: "Package to upload"
required: true
type: choice
options:
- dms
- dms-greeter
- dms-git
- all
default: "dms"
description: "Package to upload (dms, dms-git, dms-greeter, or all)"
required: false
default: "dms-git"
rebuild_release:
description: "Release number for rebuilds (e.g., 2, 3, 4 for ppa2, ppa3, ppa4)"
required: false
@@ -145,7 +139,7 @@ jobs:
fi
else
# Fallback
echo "packages=dms" >> $GITHUB_OUTPUT
echo "packages=dms-git" >> $GITHUB_OUTPUT
echo "has_updates=true" >> $GITHUB_OUTPUT
fi
@@ -215,7 +209,7 @@ jobs:
echo "✓ Using rebuild release number: ppa$REBUILD_RELEASE"
fi
# PACKAGES can be space-separated list (e.g., "dms-git dms dms-greeter" from "all" check)
# PACKAGES can be space-separated list (e.g., "dms-git dms" from "all" check)
# Loop through each package and upload
for PKG in $PACKAGES; do
# Map package to PPA name

View File

@@ -16,8 +16,6 @@ require (
github.com/sblinch/kdl-go v0.0.0-20260121213736-8b7053306ca6
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
github.com/yeqown/go-qrcode/v2 v2.2.5
github.com/yeqown/go-qrcode/writer/standard v1.3.0
github.com/yuin/goldmark v1.7.16
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
go.etcd.io/bbolt v1.4.3
@@ -34,19 +32,15 @@ require (
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/go-git/gcfg/v2 v2.0.2 // indirect
github.com/go-git/go-billy/v6 v6.0.0-20260209124918-37866f83c2d3 // indirect
github.com/go-logfmt/logfmt v0.6.1 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/kevinburke/ssh_config v1.6.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/pjbgf/sha1cd v0.5.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/stretchr/objx v0.5.3 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/net v0.50.0 // indirect
)

View File

@@ -58,8 +58,6 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
@@ -77,8 +75,6 @@ github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -119,8 +115,6 @@ github.com/pilebones/go-udev v0.9.1 h1:uN72M1C1fgzhsVmBGEM8w9RD1JY4iVsPZpr+Z6rb3
github.com/pilebones/go-udev v0.9.1/go.mod h1:Bgcl07crebF3JSeS4+nuaRvhWFdCeFoBhXXeAp93XNo=
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@@ -148,12 +142,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yeqown/go-qrcode/v2 v2.2.5 h1:HCOe2bSjkhZyYoyyNaXNzh4DJZll6inVJQQw+8228Zk=
github.com/yeqown/go-qrcode/v2 v2.2.5/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw=
github.com/yeqown/go-qrcode/writer/standard v1.3.0 h1:chdyhEfRtUPgQtuPeaWVGQ/TQx4rE1PqeoW3U+53t34=
github.com/yeqown/go-qrcode/writer/standard v1.3.0/go.mod h1:O4MbzsotGCvy8upYPCR91j81dr5XLT7heuljcNXW+oQ=
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE=
github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=

View File

@@ -1062,62 +1062,6 @@ func (_c *MockBackend_GetWiFiNetworkDetails_Call) RunAndReturn(run func(string)
return _c
}
// GetWiFiQRCodeContent provides a mock function with given fields: ssid
func (_m *MockBackend) GetWiFiQRCodeContent(ssid string) (string, error) {
ret := _m.Called(ssid)
if len(ret) == 0 {
panic("no return value specified for GetWiFiQRCodeContent")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(ssid)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(ssid)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(ssid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockBackend_GetWiFiQRCodeContent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetWiFiQRCodeContent'
type MockBackend_GetWiFiQRCodeContent_Call struct {
*mock.Call
}
// GetWiFiQRCodeContent is a helper method to define mock.On call
// - ssid string
func (_e *MockBackend_Expecter) GetWiFiQRCodeContent(ssid interface{}) *MockBackend_GetWiFiQRCodeContent_Call {
return &MockBackend_GetWiFiQRCodeContent_Call{Call: _e.mock.On("GetWiFiQRCodeContent", ssid)}
}
func (_c *MockBackend_GetWiFiQRCodeContent_Call) Run(run func(ssid string)) *MockBackend_GetWiFiQRCodeContent_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockBackend_GetWiFiQRCodeContent_Call) Return(_a0 string, _a1 error) *MockBackend_GetWiFiQRCodeContent_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockBackend_GetWiFiQRCodeContent_Call) RunAndReturn(run func(string) (string, error)) *MockBackend_GetWiFiQRCodeContent_Call {
_c.Call.Return(run)
return _c
}
// GetWiredConnections provides a mock function with no fields
func (_m *MockBackend) GetWiredConnections() ([]network.WiredConnection, error) {
ret := _m.Called()

View File

@@ -10,7 +10,6 @@ type Backend interface {
ScanWiFi() error
ScanWiFiDevice(device string) error
GetWiFiNetworkDetails(ssid string) (*NetworkInfoResponse, error)
GetWiFiQRCodeContent(ssid string) (string, error)
GetWiFiDevices() []WiFiDevice
ConnectWiFi(req ConnectionRequest) error

View File

@@ -111,10 +111,6 @@ func (b *HybridIwdNetworkdBackend) GetWiFiNetworkDetails(ssid string) (*NetworkI
return b.wifi.GetWiFiNetworkDetails(ssid)
}
func (b *HybridIwdNetworkdBackend) GetWiFiQRCodeContent(ssid string) (string, error) {
return b.wifi.GetWiFiQRCodeContent(ssid)
}
func (b *HybridIwdNetworkdBackend) ConnectWiFi(req ConnectionRequest) error {
if err := b.wifi.ConnectWiFi(req); err != nil {
return err

View File

@@ -1,9 +1,6 @@
package network
import (
"fmt"
"os"
)
import "fmt"
func (b *IWDBackend) GetWiredConnections() ([]WiredConnection, error) {
return nil, fmt.Errorf("wired connections not supported by iwd")
@@ -115,19 +112,3 @@ func (b *IWDBackend) getWiFiDevicesLocked() []WiFiDevice {
Networks: b.state.WiFiNetworks,
}}
}
func (b *IWDBackend) GetWiFiQRCodeContent(ssid string) (string, error) {
path := iwdConfigPath(ssid)
data, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("no saved iwd config for `%s`: %w", ssid, err)
}
passphrase, err := parseIWDPassphrase(string(data))
if err != nil {
return "", fmt.Errorf("failed to read passphrase for `%s`: %w", ssid, err)
}
return FormatWiFiQRString("WPA", ssid, passphrase), nil
}

View File

@@ -18,10 +18,6 @@ func (b *SystemdNetworkdBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInf
return nil, fmt.Errorf("WiFi details not supported by networkd backend")
}
func (b *SystemdNetworkdBackend) GetWiFiQRCodeContent(ssid string) (string, error) {
return "", fmt.Errorf("WiFi QR Code not supported by networkd backend")
}
func (b *SystemdNetworkdBackend) ConnectWiFi(req ConnectionRequest) error {
return fmt.Errorf("WiFi connect not supported by networkd backend")
}

View File

@@ -196,65 +196,6 @@ func (b *NetworkManagerBackend) GetWiFiNetworkDetails(ssid string) (*NetworkInfo
}, nil
}
func (b *NetworkManagerBackend) GetWiFiQRCodeContent(ssid string) (string, error) {
conn, err := b.findConnection(ssid)
if err != nil {
return "", fmt.Errorf("no saved connection for `%s`: %w", ssid, err)
}
connSettings, err := conn.GetSettings()
if err != nil {
return "", fmt.Errorf("failed to get settings for `%s`: %w", ssid, err)
}
secSettings, ok := connSettings["802-11-wireless-security"]
if !ok {
return "", fmt.Errorf("network `%s` has no security settings", ssid)
}
keyMgmt, ok := secSettings["key-mgmt"].(string)
if !ok {
return "", fmt.Errorf("failed to identify security type of network `%s`", ssid)
}
var securityType string
switch keyMgmt {
case "none":
authAlg, _ := secSettings["auth-alg"].(string)
switch authAlg {
case "open":
securityType = "nopass"
default:
securityType = "WEP"
}
case "ieee8021x":
securityType = "WEP"
default:
securityType = "WPA"
}
if securityType != "WPA" {
return "", fmt.Errorf("QR code generation only supports WPA connections, `%s` uses %s", ssid, securityType)
}
secrets, err := conn.GetSecrets("802-11-wireless-security")
if err != nil {
return "", fmt.Errorf("failed to retrieve connection secrets for `%s`: %w", ssid, err)
}
secSecrets, ok := secrets["802-11-wireless-security"]
if !ok {
return "", fmt.Errorf("failed to retrieve password for `%s`", ssid)
}
psk, ok := secSecrets["psk"].(string)
if !ok {
return "", fmt.Errorf("failed to retrieve password for `%s`", ssid)
}
return FormatWiFiQRString(securityType, ssid, psk), nil
}
func (b *NetworkManagerBackend) ConnectWiFi(req ConnectionRequest) error {
devInfo, err := b.getWifiDeviceForConnection(req.Device)
if err != nil {

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"net"
"os"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
@@ -41,10 +40,6 @@ func HandleRequest(conn net.Conn, req models.Request, manager *Manager) {
handleSetPreference(conn, req, manager)
case "network.info":
handleGetNetworkInfo(conn, req, manager)
case "network.qrcode":
handleGetNetworkQRCode(conn, req, manager)
case "network.delete-qrcode":
handleDeleteQRCode(conn, req, manager)
case "network.ethernet.info":
handleGetWiredNetworkInfo(conn, req, manager)
case "network.subscribe":
@@ -325,42 +320,6 @@ func handleGetNetworkInfo(conn net.Conn, req models.Request, manager *Manager) {
models.Respond(conn, req.ID, network)
}
func handleGetNetworkQRCode(conn net.Conn, req models.Request, manager *Manager) {
ssid, err := params.String(req.Params, "ssid")
if err != nil {
models.RespondError(conn, req.ID, err.Error())
return
}
content, err := manager.GetNetworkQRCode(ssid)
if err != nil {
models.RespondError(conn, req.ID, err.Error())
return
}
models.Respond(conn, req.ID, content)
}
func handleDeleteQRCode(conn net.Conn, req models.Request, _ *Manager) {
path, err := params.String(req.Params, "path")
if err != nil {
models.RespondError(conn, req.ID, err.Error())
return
}
if !isValidQRCodePath(path) {
models.RespondError(conn, req.ID, "invalid QR code path")
return
}
if err := os.Remove(path); err != nil {
models.RespondError(conn, req.ID, err.Error())
return
}
models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "QR code file deleted"})
}
func handleGetWiredNetworkInfo(conn net.Conn, req models.Request, manager *Manager) {
uuid, err := params.String(req.Params, "uuid")
if err != nil {

View File

@@ -6,8 +6,6 @@ import (
"time"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
"github.com/yeqown/go-qrcode/v2"
"github.com/yeqown/go-qrcode/writer/standard"
)
func NewManager() (*Manager, error) {
@@ -440,43 +438,6 @@ func (m *Manager) GetNetworkInfoDetailed(ssid string) (*NetworkInfoResponse, err
return m.backend.GetWiFiNetworkDetails(ssid)
}
func (m *Manager) GetNetworkQRCode(ssid string) ([2]string, error) {
content, err := m.backend.GetWiFiQRCodeContent(ssid)
if err != nil {
return [2]string{}, err
}
qrc, err := qrcode.New(content)
if err != nil {
return [2]string{}, fmt.Errorf("failed to create QR code for `%s`: %w", ssid, err)
}
pathThemed, pathNormal := qrCodePaths(ssid)
wThemed, err := standard.New(
pathThemed,
standard.WithBuiltinImageEncoder(standard.PNG_FORMAT),
standard.WithBgTransparent(),
standard.WithFgColorRGBHex("#ffffff"),
)
if err != nil {
return [2]string{}, fmt.Errorf("failed to create QR code writer: %w", err)
}
if err := qrc.Save(wThemed); err != nil {
return [2]string{}, fmt.Errorf("failed to save QR code for `%s`: %w", ssid, err)
}
wNormal, err := standard.New(pathNormal, standard.WithBuiltinImageEncoder(standard.PNG_FORMAT))
if err != nil {
return [2]string{}, fmt.Errorf("failed to create QR code writer: %w", err)
}
if err := qrc.Save(wNormal); err != nil {
return [2]string{}, fmt.Errorf("failed to save QR code for `%s`: %w", ssid, err)
}
return [2]string{pathThemed, pathNormal}, nil
}
func (m *Manager) ToggleWiFi() error {
enabled, err := m.backend.GetWiFiEnabled()
if err != nil {

View File

@@ -1,59 +0,0 @@
package network
import (
"fmt"
"path/filepath"
"regexp"
"strings"
)
const qrCodeTmpPrefix = "/tmp/dank-wifi-qrcode-"
func FormatWiFiQRString(securityType, ssid, password string) string {
return fmt.Sprintf("WIFI:T:%s;S:%s;P:%s;;", securityType, ssid, password)
}
func qrCodePaths(ssid string) (themed, normal string) {
safe := sanitizeSSIDForPath(ssid)
themed = fmt.Sprintf("%s%s-themed.png", qrCodeTmpPrefix, safe)
normal = fmt.Sprintf("%s%s-normal.png", qrCodeTmpPrefix, safe)
return
}
func isValidQRCodePath(path string) bool {
clean := filepath.Clean(path)
return strings.HasPrefix(clean, qrCodeTmpPrefix) && strings.HasSuffix(clean, ".png")
}
var safePathChar = regexp.MustCompile(`[^a-zA-Z0-9_-]`)
func sanitizeSSIDForPath(ssid string) string {
return safePathChar.ReplaceAllString(ssid, "_")
}
var iwdVerbatimSSID = regexp.MustCompile(`^[a-zA-Z0-9 _-]+$`)
func iwdConfigPath(ssid string) string {
switch {
case iwdVerbatimSSID.MatchString(ssid):
return fmt.Sprintf("/var/lib/iwd/%s.psk", ssid)
default:
return fmt.Sprintf("/var/lib/iwd/=%x.psk", []byte(ssid))
}
}
func parseIWDPassphrase(data string) (string, error) {
inSecurity := false
for _, line := range strings.Split(data, "\n") {
line = strings.TrimSpace(line)
switch {
case line == "[Security]":
inSecurity = true
case strings.HasPrefix(line, "["):
inSecurity = false
case inSecurity && strings.HasPrefix(line, "Passphrase="):
return strings.TrimPrefix(line, "Passphrase="), nil
}
}
return "", fmt.Errorf("no passphrase found in iwd config")
}

View File

@@ -27,12 +27,12 @@ override_dh_auto_build:
# Verify core directory exists (native package format has source at root)
test -d core || (echo "ERROR: core directory not found!" && exit 1)
# Pin go.mod and vendor/modules.txt to the installed Go toolchain version
GO_INSTALLED=$$(go version | grep -oP 'go\K[0-9]+\.[0-9]+'); \
sed -i "s/^go [0-9]\+\.[0-9]\+\(\.[0-9]*\)\?$$/go $${GO_INSTALLED}/" core/go.mod; \
sed -i "s/^\(## explicit; go \)[0-9]\+\.[0-9]\+\(\.[0-9]*\)\?$$/\1$${GO_INSTALLED}/" core/vendor/modules.txt
# Patch go.mod to use Go 1.24 base version (Debian 13 has 1.23.x, may vary)
sed -i 's/^go 1\.24\.[0-9]*/go 1.24/' core/go.mod
# Build dms-cli (single shell to preserve variables; arch: Debian amd64/arm64 -> Makefile amd64/arm64)
# Build dms-cli from source using vendored dependencies
# Extract version info and build in single shell to preserve variables
# Architecture mapping: Debian amd64/arm64 -> Makefile amd64/arm64
VERSION="$(UPSTREAM_VERSION)"; \
COMMIT=$$(echo "$(UPSTREAM_VERSION)" | grep -oP '(?<=git)[0-9]+\.[a-f0-9]+' | cut -d. -f2 | head -c8 || echo "unknown"); \
if [ "$(DEB_HOST_ARCH)" = "amd64" ]; then \

View File

@@ -3,7 +3,7 @@
<service name="download_url">
<param name="protocol">https</param>
<param name="host">github.com</param>
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.4.3/dms-qml.tar.gz</param>
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.4.2/dms-qml.tar.gz</param>
<param name="filename">dms-qml.tar.gz</param>
</service>
</services>

View File

@@ -1,5 +1,6 @@
dms-greeter (1.4.3db1) unstable; urgency=medium
dms-greeter (1.4.2db8) unstable; urgency=medium
* Update to v1.4.3 stable release
* Initial Debian OBS package
* Port from Ubuntu/Fedora packaging
-- Avenge Media <AvengeMedia.US@gmail.com> Tue, 25 Feb 2026 02:40:00 +0000
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 21 Feb 2026 00:00:00 +0000

View File

@@ -3,7 +3,6 @@
%global debug_package %{nil}
%global version {{{ git_repo_version }}}
%global pkg_summary DankMaterialShell - Material 3 inspired shell for Wayland compositors
%global go_toolchain_version 1.25.7
Name: dms
Epoch: 2
@@ -15,12 +14,12 @@ License: MIT
URL: https://github.com/AvengeMedia/DankMaterialShell
VCS: {{{ git_repo_vcs }}}
Source0: {{{ git_repo_pack }}}
Source1: https://go.dev/dl/go%{go_toolchain_version}.linux-amd64.tar.gz
Source2: https://go.dev/dl/go%{go_toolchain_version}.linux-arm64.tar.gz
BuildRequires: git-core
BuildRequires: gzip
BuildRequires: golang >= 1.24
BuildRequires: make
BuildRequires: wget
BuildRequires: systemd-rpm-macros
# Core requirements
@@ -29,7 +28,7 @@ Requires: accountsservice
Requires: dms-cli = %{epoch}:%{version}-%{release}
Requires: dgop
# Core utilities (Recommended for DMS functionality)
# Core utilities (Highly recommended for DMS functionality)
Recommends: cava
Recommends: danksearch
Recommends: matugen
@@ -67,28 +66,6 @@ Provides native DBus bindings, NetworkManager integration, and system utilities.
VERSION="%{version}"
COMMIT=$(echo "%{version}" | grep -oP '[a-f0-9]{7,}' | head -n1 || echo "unknown")
# Use pinned bundled Go toolchain (deterministic across chroots)
case "%{_arch}" in
x86_64)
GO_TARBALL="%{_sourcedir}/go%{go_toolchain_version}.linux-amd64.tar.gz"
;;
aarch64)
GO_TARBALL="%{_sourcedir}/go%{go_toolchain_version}.linux-arm64.tar.gz"
;;
*)
echo "Unsupported architecture for bundled Go: %{_arch}"
exit 1
;;
esac
rm -rf .go
tar -xzf "$GO_TARBALL"
mv go .go
export GOROOT="$PWD/.go"
export PATH="$GOROOT/bin:$PATH"
export GOTOOLCHAIN=local
go version
cd core
make dist VERSION="$VERSION" COMMIT="$COMMIT"

View File

@@ -56,10 +56,8 @@ mkdir -p $HOME $GOCACHE $GOMODCACHE
# OBS has no network access, so use local toolchain only
export GOTOOLCHAIN=local
# Pin go.mod and vendor/modules.txt to the installed Go toolchain version
GO_INSTALLED=$(go version | grep -oP 'go\K[0-9]+\.[0-9]+')
sed -i "s/^go [0-9]\+\.[0-9]\+\(\.[0-9]*\)\?$/go ${GO_INSTALLED}/" core/go.mod
sed -i "s/^\(## explicit; go \)[0-9]\+\.[0-9]\+\(\.[0-9]*\)\?$/\1${GO_INSTALLED}/" core/vendor/modules.txt
# Patch go.mod to use base Go version (e.g., go 1.24 instead of go 1.24.6)
sed -i 's/^go 1\.24\.[0-9]*/go 1.24/' core/go.mod
# Extract version info for embedding in binary
VERSION="%{version}"

View File

@@ -419,9 +419,6 @@ if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ -f "distro/opensuse/$PACKAGE.spec" ]];
sed -i "s/VERSION_PLACEHOLDER/${DMS_GREETER_BASE_VERSION}/g" "$WORK_DIR/$PACKAGE.spec"
sed -i "s/RELEASE_PLACEHOLDER/${DMS_GREETER_RELEASE}/g" "$WORK_DIR/$PACKAGE.spec"
sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" "$WORK_DIR/$PACKAGE.spec"
# Explicitly set Version:/Release: in case the spec uses %{version} macro
sed -i "s/^Version:.*/Version: ${DMS_GREETER_BASE_VERSION}/" "$WORK_DIR/$PACKAGE.spec"
sed -i "s/^Release:.*/Release: ${DMS_GREETER_RELEASE}%{?dist}/" "$WORK_DIR/$PACKAGE.spec"
fi
if [[ -f "$WORK_DIR/.osc/$PACKAGE.spec" ]]; then
@@ -816,9 +813,6 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
sed -i "s/VERSION_PLACEHOLDER/${DMS_GREETER_BASE_VERSION}/g" "$WORK_DIR/$PACKAGE.spec"
sed -i "s/RELEASE_PLACEHOLDER/${DMS_GREETER_RELEASE}/g" "$WORK_DIR/$PACKAGE.spec"
sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" "$WORK_DIR/$PACKAGE.spec"
# Explicitly set Version:/Release: in case the spec uses %{version} macro
sed -i "s/^Version:.*/Version: ${DMS_GREETER_BASE_VERSION}/" "$WORK_DIR/$PACKAGE.spec"
sed -i "s/^Release:.*/Release: ${DMS_GREETER_RELEASE}%{?dist}/" "$WORK_DIR/$PACKAGE.spec"
fi
fi

View File

@@ -182,7 +182,6 @@
with pkgs;
[
go_1_25
go-mockery_2
gopls
delve
go-tools

View File

@@ -1 +1 @@
The Wolverine
Saffron Bloom

View File

@@ -1,54 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import qs.Common
Item {
id: root
property var level: Theme.elevationLevel2
property string direction: Theme.elevationLightDirection
property real fallbackOffset: 4
property color targetColor: "white"
property real targetRadius: Theme.cornerRadius
property color borderColor: "transparent"
property real borderWidth: 0
property bool shadowEnabled: Theme.elevationEnabled
property real shadowBlurPx: level && level.blurPx !== undefined ? level.blurPx : 0
property real shadowSpreadPx: level && level.spreadPx !== undefined ? level.spreadPx : 0
property real shadowOffsetX: Theme.elevationOffsetXFor(level, direction, fallbackOffset)
property real shadowOffsetY: Theme.elevationOffsetYFor(level, direction, fallbackOffset)
property color shadowColor: Theme.elevationShadowColor(level)
property real shadowOpacity: 1
property real blurMax: Theme.elevationBlurMax
property alias sourceRect: sourceRect
layer.enabled: shadowEnabled
layer.effect: MultiEffect {
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, root.shadowBlurPx / Math.max(1, root.blurMax)))
shadowScale: 1 + (2 * root.shadowSpreadPx) / Math.max(1, Math.min(root.width, root.height))
shadowHorizontalOffset: root.shadowOffsetX
shadowVerticalOffset: root.shadowOffsetY
blurMax: root.blurMax
shadowColor: root.shadowColor
shadowOpacity: root.shadowOpacity
}
Rectangle {
id: sourceRect
anchors.fill: parent
radius: root.targetRadius
color: root.targetColor
border.color: root.borderColor
border.width: root.borderWidth
}
}

View File

@@ -14,7 +14,7 @@ import "settings/SettingsStore.js" as Store
Singleton {
id: root
readonly property int settingsConfigVersion: 6
readonly property int settingsConfigVersion: 5
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
@@ -165,24 +165,6 @@ Singleton {
property int modalCustomAnimationDuration: 150
property bool enableRippleEffects: true
onEnableRippleEffectsChanged: saveSettings()
property bool m3ElevationEnabled: true
onM3ElevationEnabledChanged: saveSettings()
property int m3ElevationIntensity: 12
onM3ElevationIntensityChanged: saveSettings()
property int m3ElevationOpacity: 30
onM3ElevationOpacityChanged: saveSettings()
property string m3ElevationColorMode: "default"
onM3ElevationColorModeChanged: saveSettings()
property string m3ElevationLightDirection: "top"
onM3ElevationLightDirectionChanged: saveSettings()
property string m3ElevationCustomColor: "#000000"
onM3ElevationCustomColorChanged: saveSettings()
property bool modalElevationEnabled: true
onModalElevationEnabledChanged: saveSettings()
property bool popoutElevationEnabled: true
onPopoutElevationEnabledChanged: saveSettings()
property bool barElevationEnabled: true
onBarElevationEnabledChanged: saveSettings()
property string wallpaperFillMode: "Fill"
property bool blurredWallpaperLayer: false
property bool blurWallpaperOnOverview: false
@@ -620,7 +602,7 @@ Singleton {
"scrollYBehavior": "workspace",
"shadowIntensity": 0,
"shadowOpacity": 60,
"shadowColorMode": "default",
"shadowColorMode": "text",
"shadowCustomColor": "#000000",
"clickThrough": false
}

View File

@@ -673,232 +673,6 @@ Singleton {
property color shadowMedium: Qt.rgba(0, 0, 0, 0.08)
property color shadowStrong: Qt.rgba(0, 0, 0, 0.3)
readonly property bool elevationEnabled: typeof SettingsData !== "undefined" && (SettingsData.m3ElevationEnabled ?? true)
readonly property real elevationBlurMax: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? Math.min(128, Math.max(32, SettingsData.m3ElevationIntensity * 2)) : 64
readonly property real _elevMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? SettingsData.m3ElevationIntensity / 12 : 1
readonly property real _opMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationOpacity !== undefined ? SettingsData.m3ElevationOpacity / 60 : 1
function normalizeElevationDirection(direction) {
switch (direction) {
case "top":
case "topLeft":
case "topRight":
case "bottom":
case "bottomLeft":
case "bottomRight":
case "left":
case "right":
case "autoBar":
return direction;
default:
return "top";
}
}
readonly property string elevationLightDirection: {
if (typeof SettingsData === "undefined" || !SettingsData.m3ElevationLightDirection)
return "top";
switch (SettingsData.m3ElevationLightDirection) {
case "autoBar":
case "top":
case "topLeft":
case "topRight":
case "bottom":
return SettingsData.m3ElevationLightDirection;
default:
return "top";
}
}
readonly property real _elevDiagRatio: 0.55
readonly property string _globalElevationDirForTokens: {
const normalized = normalizeElevationDirection(elevationLightDirection);
return normalized === "autoBar" ? "top" : normalized;
}
readonly property real _elevDirX: {
switch (_globalElevationDirForTokens) {
case "topLeft":
case "bottomLeft":
case "left":
return 1;
case "topRight":
case "bottomRight":
case "right":
return -1;
default:
return 0;
}
}
readonly property real _elevDirY: {
switch (_globalElevationDirForTokens) {
case "bottom":
case "bottomLeft":
case "bottomRight":
return -1;
case "left":
case "right":
return 0;
default:
return 1;
}
}
readonly property real _elevDirXScale: (_globalElevationDirForTokens === "left" || _globalElevationDirForTokens === "right") ? 1 : _elevDiagRatio
readonly property var elevationLevel1: ({
blurPx: 4 * _elevMult,
offsetX: 1 * _elevMult * _elevDirXScale * _elevDirX,
offsetY: 1 * _elevMult * _elevDirY,
spreadPx: 0,
alpha: 0.2 * _opMult
})
readonly property var elevationLevel2: ({
blurPx: 8 * _elevMult,
offsetX: 4 * _elevMult * _elevDirXScale * _elevDirX,
offsetY: 4 * _elevMult * _elevDirY,
spreadPx: 0,
alpha: 0.25 * _opMult
})
readonly property var elevationLevel3: ({
blurPx: 12 * _elevMult,
offsetX: 6 * _elevMult * _elevDirXScale * _elevDirX,
offsetY: 6 * _elevMult * _elevDirY,
spreadPx: 0,
alpha: 0.3 * _opMult
})
readonly property var elevationLevel4: ({
blurPx: 16 * _elevMult,
offsetX: 8 * _elevMult * _elevDirXScale * _elevDirX,
offsetY: 8 * _elevMult * _elevDirY,
spreadPx: 0,
alpha: 0.3 * _opMult
})
readonly property var elevationLevel5: ({
blurPx: 20 * _elevMult,
offsetX: 10 * _elevMult * _elevDirXScale * _elevDirX,
offsetY: 10 * _elevMult * _elevDirY,
spreadPx: 0,
alpha: 0.3 * _opMult
})
function elevationOffsetMagnitude(level, fallback, direction) {
if (!level) {
return fallback !== undefined ? Math.abs(fallback) : 0;
}
const yMag = Math.abs(level.offsetY !== undefined ? level.offsetY : 0);
if (yMag > 0)
return yMag;
const xMag = Math.abs(level.offsetX !== undefined ? level.offsetX : 0);
if (xMag > 0) {
if (direction === "left" || direction === "right")
return xMag;
return xMag / _elevDiagRatio;
}
return fallback !== undefined ? Math.abs(fallback) : 0;
}
function elevationOffsetXFor(level, direction, fallback) {
const dir = normalizeElevationDirection(direction || elevationLightDirection);
const mag = elevationOffsetMagnitude(level, fallback, dir);
switch (dir) {
case "topLeft":
case "bottomLeft":
return mag * _elevDiagRatio;
case "topRight":
case "bottomRight":
return -mag * _elevDiagRatio;
case "left":
return mag;
case "right":
return -mag;
default:
return 0;
}
}
function elevationOffsetYFor(level, direction, fallback) {
const dir = normalizeElevationDirection(direction || elevationLightDirection);
const mag = elevationOffsetMagnitude(level, fallback, dir);
switch (dir) {
case "bottom":
case "bottomLeft":
case "bottomRight":
return -mag;
case "left":
case "right":
return 0;
default:
return mag;
}
}
function elevationOffsetX(level, fallback) {
return elevationOffsetXFor(level, elevationLightDirection, fallback);
}
function elevationOffsetY(level, fallback) {
return elevationOffsetYFor(level, elevationLightDirection, fallback);
}
function elevationRenderPadding(level, direction, fallbackOffset, extraPadding, minPadding) {
const dir = direction !== undefined ? direction : elevationLightDirection;
const blur = (level && level.blurPx !== undefined) ? Math.max(0, level.blurPx) : 0;
const spread = (level && level.spreadPx !== undefined) ? Math.max(0, level.spreadPx) : 0;
const fallback = fallbackOffset !== undefined ? fallbackOffset : 0;
const extra = extraPadding !== undefined ? extraPadding : 8;
const minPad = minPadding !== undefined ? minPadding : 16;
const offsetX = Math.abs(elevationOffsetXFor(level, dir, fallback));
const offsetY = Math.abs(elevationOffsetYFor(level, dir, fallback));
return Math.max(minPad, blur + spread + Math.max(offsetX, offsetY) + extra);
}
function elevationShadowColor(level) {
const alpha = (level && level.alpha !== undefined) ? level.alpha : 0.3;
let r = 0;
let g = 0;
let b = 0;
if (typeof SettingsData !== "undefined") {
const mode = SettingsData.m3ElevationColorMode || "default";
if (mode === "default") {
r = 0;
g = 0;
b = 0;
} else if (mode === "text") {
r = surfaceText.r;
g = surfaceText.g;
b = surfaceText.b;
} else if (mode === "primary") {
r = primary.r;
g = primary.g;
b = primary.b;
} else if (mode === "surfaceVariant") {
r = surfaceVariant.r;
g = surfaceVariant.g;
b = surfaceVariant.b;
} else if (mode === "custom" && SettingsData.m3ElevationCustomColor) {
const c = Qt.color(SettingsData.m3ElevationCustomColor);
r = c.r;
g = c.g;
b = c.b;
}
}
return Qt.rgba(r, g, b, alpha);
}
function elevationTintOpacity(level) {
if (!level)
return 0;
if (level === elevationLevel1)
return 0.05;
if (level === elevationLevel2)
return 0.08;
if (level === elevationLevel3)
return 0.11;
if (level === elevationLevel4)
return 0.12;
if (level === elevationLevel5)
return 0.14;
return 0.08;
}
readonly property var animationDurations: [
{
"shorter": 0,

View File

@@ -21,7 +21,7 @@ var SPEC = {
widgetColorMode: { def: "default" },
controlCenterTileColorMode: { def: "primary" },
buttonColorMode: { def: "primary" },
cornerRadius: { def: 16, onChange: "updateCompositorLayout" },
cornerRadius: { def: 12, onChange: "updateCompositorLayout" },
niriLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
niriLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
niriLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
@@ -46,15 +46,6 @@ var SPEC = {
modalAnimationSpeed: { def: 1 },
modalCustomAnimationDuration: { def: 150 },
enableRippleEffects: { def: true },
m3ElevationEnabled: { def: true },
m3ElevationIntensity: { def: 12 },
m3ElevationOpacity: { def: 30 },
m3ElevationColorMode: { def: "default" },
m3ElevationLightDirection: { def: "top" },
m3ElevationCustomColor: { def: "#000000" },
modalElevationEnabled: { def: true },
popoutElevationEnabled: { def: true },
barElevationEnabled: { def: true },
wallpaperFillMode: { def: "Fill" },
blurredWallpaperLayer: { def: false },
blurWallpaperOnOverview: { def: false },
@@ -434,7 +425,7 @@ var SPEC = {
scrollYBehavior: "workspace",
shadowIntensity: 0,
shadowOpacity: 60,
shadowColorMode: "default",
shadowColorMode: "text",
shadowCustomColor: "#000000",
clickThrough: false
}], onChange: "updateBarConfigs"

View File

@@ -226,25 +226,6 @@ function migrateToVersion(obj, targetVersion) {
settings.configVersion = 5;
}
if (currentVersion < 6) {
console.info("Migrating settings from version", currentVersion, "to version 6");
if (settings.barElevationEnabled === undefined) {
var legacyBars = Array.isArray(settings.barConfigs) ? settings.barConfigs : [];
var hadLegacyBarShadowEnabled = false;
for (var j = 0; j < legacyBars.length; j++) {
var legacyIntensity = Number(legacyBars[j] && legacyBars[j].shadowIntensity);
if (!isNaN(legacyIntensity) && legacyIntensity > 0) {
hadLegacyBarShadowEnabled = true;
break;
}
}
settings.barElevationEnabled = hadLegacyBarShadowEnabled;
}
settings.configVersion = 6;
}
return settings;
}

View File

@@ -365,23 +365,6 @@ Item {
}
}
LazyLoader {
id: wifiQRCodeModalLoader
active: false
Component.onCompleted: {
PopoutService.wifiQRCodeModalLoader = wifiQRCodeModalLoader;
}
WifiQRCodeModal {
id: wifiQRCodeModalItem
Component.onCompleted: {
PopoutService.wifiQRCodeModal = wifiQRCodeModalItem;
}
}
}
LazyLoader {
id: polkitAuthModalLoader
active: false

View File

@@ -32,9 +32,9 @@ Item {
property list<real> animationExitCurve: Theme.expressiveCurves.emphasized
property color backgroundColor: Theme.surfaceContainer
property color borderColor: Theme.outlineMedium
property real borderWidth: 0
property real borderWidth: 1
property real cornerRadius: Theme.cornerRadius
property bool enableShadow: true
property bool enableShadow: false
property alias modalFocusScope: focusScope
property bool shouldBeVisible: false
property bool shouldHaveFocus: shouldBeVisible
@@ -142,11 +142,7 @@ Item {
}
}
readonly property var shadowLevel: Theme.elevationLevel3
readonly property real shadowFallbackOffset: 6
readonly property real shadowRenderPadding: (root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, Theme.elevationLightDirection, shadowFallbackOffset, 8, 16) : 0
readonly property real shadowMotionPadding: animationType === "slide" ? 30 : Math.max(0, animationOffset)
readonly property real shadowBuffer: Theme.snap(shadowRenderPadding + shadowMotionPadding, dpr)
readonly property real shadowBuffer: 5
readonly property real alignedWidth: Theme.px(modalWidth, dpr)
readonly property real alignedHeight: Theme.px(modalHeight, dpr)
@@ -381,16 +377,12 @@ Item {
}
}
ElevationShadow {
id: modalShadowLayer
Rectangle {
anchors.fill: parent
level: root.shadowLevel
fallbackOffset: root.shadowFallbackOffset
targetRadius: root.cornerRadius
targetColor: root.backgroundColor
borderColor: root.borderColor
borderWidth: root.borderWidth
shadowEnabled: root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
color: root.backgroundColor
border.color: root.borderColor
border.width: root.borderWidth
radius: root.cornerRadius
}
FocusScope {

View File

@@ -162,11 +162,6 @@ Item {
}
]
property string fileSearchType: "all"
property string fileSearchExt: ""
property string fileSearchFolder: ""
property string fileSearchSort: "score"
property string pluginFilter: ""
property string activePluginName: ""
property var activePluginCategories: []
@@ -351,10 +346,6 @@ Item {
previousSearchMode = "all";
autoSwitchedToFiles = false;
isFileSearching = false;
fileSearchType = "all";
fileSearchExt = "";
fileSearchFolder = "";
fileSearchSort = "score";
sections = [];
flatModel = [];
selectedFlatIndex = 0;
@@ -408,34 +399,6 @@ Item {
performSearch();
}
function setFileSearchType(type) {
if (fileSearchType === type)
return;
fileSearchType = type;
performFileSearch();
}
function setFileSearchExt(ext) {
if (fileSearchExt === ext)
return;
fileSearchExt = ext;
performFileSearch();
}
function setFileSearchFolder(folder) {
if (fileSearchFolder === folder)
return;
fileSearchFolder = folder;
performFileSearch();
}
function setFileSearchSort(sort) {
if (fileSearchSort === sort)
return;
fileSearchSort = sort;
performFileSearch();
}
function clearPluginFilter() {
if (pluginFilter) {
pluginFilter = "";
@@ -864,20 +827,10 @@ Item {
var params = {
limit: 20,
fuzzy: true,
sort: fileSearchSort || "score",
sort: "score",
desc: true
};
if (DSearchService.supportsTypeFilter) {
params.type = (fileSearchType && fileSearchType !== "all") ? fileSearchType : "all";
}
if (fileSearchExt) {
params.ext = fileSearchExt;
}
if (fileSearchFolder) {
params.folder = fileSearchFolder;
}
DSearchService.search(fileQuery, params, function (response) {
isFileSearching = false;
if (response.error)
@@ -887,73 +840,34 @@ Item {
for (var i = 0; i < hits.length; i++) {
var hit = hits[i];
var docTypes = hit.locations?.doc_type;
var isDir = docTypes ? !!docTypes["dir"] : false;
fileItems.push(transformFileResult({
path: hit.id || "",
score: hit.score || 0,
is_dir: isDir
score: hit.score || 0
}));
}
var fileSections = [];
var showType = fileSearchType || "all";
if (showType === "all" && DSearchService.supportsTypeFilter) {
var onlyFiles = [];
var onlyDirs = [];
for (var j = 0; j < fileItems.length; j++) {
if (fileItems[j].data?.is_dir)
onlyDirs.push(fileItems[j]);
else
onlyFiles.push(fileItems[j]);
}
if (onlyFiles.length > 0) {
fileSections.push({
id: "files",
title: I18n.tr("Files"),
icon: "insert_drive_file",
priority: 4,
items: onlyFiles,
collapsed: collapsedSections["files"] || false,
flatStartIndex: 0
});
}
if (onlyDirs.length > 0) {
fileSections.push({
id: "folders",
title: I18n.tr("Folders"),
icon: "folder",
priority: 4.1,
items: onlyDirs,
collapsed: collapsedSections["folders"] || false,
flatStartIndex: 0
});
}
} else {
var filesIcon = showType === "dir" ? "folder" : showType === "file" ? "insert_drive_file" : "folder";
var filesTitle = showType === "dir" ? I18n.tr("Folders") : I18n.tr("Files");
if (fileItems.length > 0) {
fileSections.push({
id: "files",
title: filesTitle,
icon: filesIcon,
priority: 4,
items: fileItems,
collapsed: collapsedSections["files"] || false,
flatStartIndex: 0
});
}
}
var fileSection = {
id: "files",
title: I18n.tr("Files"),
icon: "folder",
priority: 4,
items: fileItems,
collapsed: collapsedSections["files"] || false,
flatStartIndex: 0
};
var newSections;
if (searchMode === "files") {
newSections = fileSections;
newSections = fileItems.length > 0 ? [fileSection] : [];
} else {
var existingNonFile = sections.filter(function (s) {
return s.id !== "files" && s.id !== "folders";
return s.id !== "files";
});
newSections = existingNonFile.concat(fileSections);
if (fileItems.length > 0) {
newSections = existingNonFile.concat([fileSection]);
} else {
newSections = existingNonFile;
}
}
newSections.sort(function (a, b) {
return a.priority - b.priority;
@@ -999,7 +913,7 @@ Item {
}
function transformFileResult(file) {
return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"), I18n.tr("Open in terminal"));
return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"));
}
function detectTrigger(query) {
@@ -1667,9 +1581,6 @@ Item {
case "copy_path":
copyToClipboard(item.data.path);
break;
case "open_terminal":
openTerminal(item.data.path);
break;
case "copy":
copyToClipboard(item.name);
break;
@@ -1751,16 +1662,6 @@ Item {
Qt.openUrlExternally("file://" + folder);
}
function openTerminal(path) {
if (!path)
return;
var terminal = Quickshell.env("TERMINAL") || "xterm";
Quickshell.execDetached({
command: [terminal],
workingDirectory: path
});
}
function copyToClipboard(text) {
if (!text)
return;

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
@@ -76,7 +75,7 @@ Item {
return Theme.primary;
}
}
readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0
readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 1
signal dialogClosed
@@ -108,10 +107,6 @@ Item {
spotlightContent.controller.activePluginId = "";
spotlightContent.controller.activePluginName = "";
spotlightContent.controller.pluginFilter = "";
spotlightContent.controller.fileSearchType = "all";
spotlightContent.controller.fileSearchExt = "";
spotlightContent.controller.fileSearchFolder = "";
spotlightContent.controller.fileSearchSort = "score";
spotlightContent.controller.collapsedSections = {};
spotlightContent.controller.selectedFlatIndex = 0;
spotlightContent.controller.selectedItem = null;
@@ -391,16 +386,12 @@ Item {
}
}
ElevationShadow {
id: launcherShadowLayer
Rectangle {
anchors.fill: parent
level: Theme.elevationLevel3
fallbackOffset: 6
targetColor: root.backgroundColor
borderColor: root.borderColor
borderWidth: root.borderWidth
targetRadius: root.cornerRadius
shadowEnabled: Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
color: root.backgroundColor
border.color: root.borderColor
border.width: root.borderWidth
radius: root.cornerRadius
}
MouseArea {

View File

@@ -116,43 +116,31 @@ function transformBuiltInLauncherItem(item, pluginId, openLabel) {
};
}
function transformFileResult(file, openLabel, openFolderLabel, copyPathLabel, openTerminalLabel) {
function transformFileResult(file, openLabel, openFolderLabel, copyPathLabel) {
var filename = file.path ? file.path.split("/").pop() : "";
var dirname = file.path ? file.path.substring(0, file.path.lastIndexOf("/")) : "";
var isDir = file.is_dir || false;
var actions = [];
if (isDir) {
if (openTerminalLabel) {
actions.push({
name: openTerminalLabel,
icon: "terminal",
action: "open_terminal"
});
}
} else {
actions.push({
name: openFolderLabel,
icon: "folder_open",
action: "open_folder"
});
}
actions.push({
name: copyPathLabel,
icon: "content_copy",
action: "copy_path"
});
return {
id: file.path || "",
type: "file",
name: filename,
subtitle: dirname,
icon: isDir ? "folder" : Utils.getFileIcon(filename),
icon: Utils.getFileIcon(filename),
iconType: "material",
section: "files",
data: file,
actions: actions,
actions: [
{
name: openFolderLabel,
icon: "folder_open",
action: "open_folder"
},
{
name: copyPathLabel,
icon: "content_copy",
action: "copy_path"
}
],
primaryAction: {
name: openLabel,
icon: "open_in_new",

View File

@@ -549,151 +549,8 @@ FocusScope {
}
Item {
id: fileFilterRow
width: parent.width
height: showFileFilters ? fileFilterContent.height : 0
visible: showFileFilters
readonly property bool showFileFilters: controller.searchMode === "files"
Behavior on height {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Row {
id: fileFilterContent
width: parent.width
spacing: Theme.spacingS
Row {
id: typeChips
anchors.verticalCenter: parent.verticalCenter
spacing: 2
visible: DSearchService.supportsTypeFilter
Repeater {
model: [
{
id: "all",
label: I18n.tr("All"),
icon: "search"
},
{
id: "file",
label: I18n.tr("Files"),
icon: "insert_drive_file"
},
{
id: "dir",
label: I18n.tr("Folders"),
icon: "folder"
}
]
Rectangle {
required property var modelData
required property int index
width: chipContent.width + Theme.spacingM * 2
height: sortDropdown.height
radius: Theme.cornerRadius
color: controller.fileSearchType === modelData.id || chipArea.containsMouse ? Theme.primaryContainer : "transparent"
Row {
id: chipContent
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
anchors.verticalCenter: parent.verticalCenter
name: modelData.icon
size: 14
color: controller.fileSearchType === modelData.id ? Theme.primary : Theme.surfaceVariantText
}
StyledText {
anchors.verticalCenter: parent.verticalCenter
text: modelData.label
font.pixelSize: Theme.fontSizeSmall
color: controller.fileSearchType === modelData.id ? Theme.primary : Theme.surfaceText
}
}
MouseArea {
id: chipArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: controller.setFileSearchType(modelData.id)
}
}
}
}
Rectangle {
width: 1
height: 20
anchors.verticalCenter: parent.verticalCenter
color: Theme.outlineMedium
visible: typeChips.visible
}
DankDropdown {
id: sortDropdown
anchors.verticalCenter: parent.verticalCenter
width: Math.min(130, parent.width / 3)
compactMode: true
dropdownWidth: 130
popupWidth: 150
maxPopupHeight: 200
currentValue: {
switch (controller.fileSearchSort) {
case "score":
return I18n.tr("Score");
case "name":
return I18n.tr("Name");
case "modified":
return I18n.tr("Modified");
case "size":
return I18n.tr("Size");
default:
return I18n.tr("Score");
}
}
options: [I18n.tr("Score"), I18n.tr("Name"), I18n.tr("Modified"), I18n.tr("Size")]
onValueChanged: value => {
var sortMap = {};
sortMap[I18n.tr("Score")] = "score";
sortMap[I18n.tr("Name")] = "name";
sortMap[I18n.tr("Modified")] = "modified";
sortMap[I18n.tr("Size")] = "size";
controller.setFileSearchSort(sortMap[value] || "score");
}
}
DankTextField {
id: extFilterField
anchors.verticalCenter: parent.verticalCenter
width: Math.min(100, parent.width / 4)
height: sortDropdown.height
placeholderText: I18n.tr("ext")
font.pixelSize: Theme.fontSizeSmall
showClearButton: text.length > 0
onTextChanged: {
controller.setFileSearchExt(text.trim());
}
}
}
}
Item {
width: parent.width
height: parent.height - searchField.height - categoryRow.height - fileFilterRow.height - actionPanel.height - Theme.spacingXS * ((categoryRow.visible ? 1 : 0) + (fileFilterRow.visible ? 1 : 0) + 2)
height: parent.height - searchField.height - categoryRow.height - actionPanel.height - Theme.spacingXS * (categoryRow.visible ? 3 : 2)
opacity: root.parentModal?.isClosing ? 0 : 1
ResultsList {
@@ -729,9 +586,6 @@ FocusScope {
function onSearchQueryRequested(query) {
searchField.text = query;
}
function onModeChanged() {
extFilterField.text = "";
}
}
FocusScope {

View File

@@ -113,7 +113,6 @@ Rectangle {
font.family: Theme.fontFamily
color: Theme.surfaceVariantText
elide: Text.ElideRight
clip: true
visible: (root.item?.subtitle ?? "").length > 0
horizontalAlignment: Text.AlignLeft
}
@@ -182,7 +181,7 @@ Rectangle {
case "plugin":
return I18n.tr("Plugin");
case "file":
return root.item.data?.is_dir ? I18n.tr("Folder") : I18n.tr("File");
return I18n.tr("File");
default:
return "";
}

View File

@@ -435,15 +435,7 @@ Item {
var mode = root.controller?.searchMode ?? "all";
switch (mode) {
case "files":
var fileType = root.controller?.fileSearchType ?? "all";
switch (fileType) {
case "dir":
return "folder_open";
case "file":
return "insert_drive_file";
default:
return "folder_open";
}
return "folder_open";
case "plugins":
return "extension";
case "apps":
@@ -473,15 +465,7 @@ Item {
return I18n.tr("Type to search files");
if (root.controller.searchQuery.length < 2)
return I18n.tr("Type at least 2 characters");
var fileType = root.controller?.fileSearchType ?? "all";
switch (fileType) {
case "dir":
return I18n.tr("No folders found");
case "file":
return I18n.tr("No files found");
default:
return I18n.tr("No results found");
}
return I18n.tr("No files found");
case "plugins":
return hasQuery ? I18n.tr("No plugin results") : I18n.tr("Browse or search plugins");
case "apps":

View File

@@ -1,170 +0,0 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import qs.Modals.Common
import qs.Modals.FileBrowser
import qs.Common
import qs.Services
import qs.Widgets
DankModal {
id: root
visible: false
layerNamespace: "dms:wifi-qrcode"
property bool disablePopupTransparency: true
property string wifiSSID: ""
property string themedQrCodePath: ""
property string normalQrCodePath: ""
modalWidth: 420
modalHeight: 480
onBackgroundClicked: hide()
onOpened: {
Qt.callLater(() => {
modalFocusScope.forceActiveFocus();
contentLoader.item.wifiSSID = wifiSSID;
contentLoader.item.themedQrCodePath = themedQrCodePath;
contentLoader.item.saveBrowserLoader = saveBrowserLoader;
});
}
function show(ssid) {
wifiSSID = ssid;
fetchNetworkQRCode(ssid);
}
function hide() {
if (themedQrCodePath !== "") {
deleteQRCodeFile(themedQrCodePath);
}
if (normalQrCodePath !== "") {
deleteQRCodeFile(normalQrCodePath);
}
close();
}
function fetchNetworkQRCode(ssid) {
// TODO: Add loading UI?
DMSService.sendRequest("network.qrcode", {
ssid: ssid
}, response => {
if (response.error) {
ToastService.showError("Failed to fetch network QR code: ", JSON.stringify(response.error));
} else if (response.result) {
themedQrCodePath = response.result[0];
normalQrCodePath = response.result[1];
open();
}
});
}
function deleteQRCodeFile(path) {
DMSService.sendRequest("network.delete-qrcode", {
path: path
}, response => {
if (response.error) {
ToastService.showError(`Failed to remove QR code at ${path}: `, JSON.stringify(response.error));
}
})
}
LazyLoader {
id: saveBrowserLoader
active: false
FileBrowserSurfaceModal {
id: saveBrowser
browserTitle: I18n.tr("Save QR Code")
browserIcon: "qr_code"
browserType: "default"
fileExtensions: ["*.png"]
allowStacking: true
saveMode: true
defaultFileName: `${root.wifiSSID ?? "wifi-qrcode"}.png`
onFileSelected: path => {
const cleanPath = decodeURI(path.toString().replace(/^file:\/\//, ''));
const fileName = cleanPath.split('/').pop();
const fileUrl = "file://" + cleanPath;
copyQrCodeProcess.exec(["cp", root.normalQrCodePath, cleanPath, "-f"])
}
Process {
id: copyQrCodeProcess
stdout: StdioCollector {
onStreamFinished: {
saveBrowser.close();
}
}
}
}
}
content: Component {
Item {
id: theItem
property alias themedQrCodePath: qrCodeImg.source
property var saveBrowserLoader: null
property string wifiSSID: ""
anchors.fill: parent
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
RowLayout {
id: modalTitle
width: parent.width
StyledText {
text: I18n.tr("WiFi QR code for ") + theItem.wifiSSID
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Bold
Layout.alignment: Qt.AlignLeft
}
DankActionButton {
iconName: "save"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: {
saveBrowserLoader.active = true;
if (saveBrowserLoader.item) {
saveBrowserLoader.item.open();
}
}
Layout.alignment: Qt.AlignRight
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: root.hide()
Layout.alignment: Qt.AlignRight
}
}
Image {
id: qrCodeImg
height: parent.height - parent.spacing - modalTitle.height
width: height
anchors.horizontalCenter: parent.horizontalCenter
MultiEffect {
source: qrCodeImg
anchors.fill: source
colorization: 1.0
colorizationColor: Theme.primary
}
}
}
}
}
}

View File

@@ -12,7 +12,7 @@ DankPopout {
id: root
layerNamespace: "dms:control-center"
fullHeightSurface: false
fullHeightSurface: true
property string expandedSection: ""
property var triggerScreen: null

View File

@@ -651,7 +651,6 @@ Rectangle {
}
Rectangle {
id: pinButton
anchors.right: parent.right
anchors.rightMargin: optionsButton.width + Theme.spacingM + Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
@@ -712,19 +711,6 @@ Rectangle {
}
}
DankActionButton {
id: qrCodeButton
visible: modelData.secured && modelData.saved
anchors.right: parent.right
anchors.rightMargin: optionsButton.width + pinWifiRow.width + 3 * Theme.spacingM + Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
iconName: "qr_code"
buttonSize: 28
onClicked: {
PopoutService.showWifiQRCodeModal(modelData.ssid);
}
}
DankRipple {
id: wifiRipple
cornerRadius: parent.radius
@@ -733,7 +719,7 @@ Rectangle {
MouseArea {
id: networkMouseArea
anchors.fill: parent
anchors.rightMargin: optionsButton.width + pinWifiRow.width + (qrCodeButton.visible ? qrCodeButton.width : 0) + Theme.spacingS * 5 + Theme.spacingM
anchors.rightMargin: optionsButton.width + Theme.spacingM + Theme.spacingS + pinWifiRow.width + Theme.spacingS * 4
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: mouse => wifiRipple.trigger(mouse.x, mouse.y)

View File

@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Shapes
import qs.Common
import qs.Services
@@ -52,43 +53,15 @@ Item {
}
}
// M3 elevation shadow — Level 2 baseline (navigation bar), with per-bar override support
readonly property bool hasPerBarOverride: (barConfig?.shadowIntensity ?? 0) > 0
readonly property var elevLevel: Theme.elevationLevel2
readonly property bool shadowEnabled: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || hasPerBarOverride
readonly property string autoBarShadowDirection: isTop ? "top" : (isBottom ? "bottom" : (isLeft ? "left" : (isRight ? "right" : "top")))
readonly property string globalShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection
readonly property string perBarShadowDirectionMode: barConfig?.shadowDirectionMode ?? "inherit"
readonly property string perBarManualShadowDirection: {
switch (barConfig?.shadowDirection) {
case "top":
case "topLeft":
case "topRight":
case "bottom":
return barConfig.shadowDirection;
default:
return "top";
}
}
readonly property string effectiveShadowDirection: {
if (!hasPerBarOverride)
return globalShadowDirection;
switch (perBarShadowDirectionMode) {
case "autoBar":
return autoBarShadowDirection;
case "manual":
return perBarManualShadowDirection === "autoBar" ? autoBarShadowDirection : perBarManualShadowDirection;
default:
return globalShadowDirection;
}
}
// Per-bar override values (when barConfig.shadowIntensity > 0)
readonly property real overrideBlurPx: (barConfig?.shadowIntensity ?? 0) * 0.2
readonly property real overrideOpacity: (barConfig?.shadowOpacity ?? 60) / 100
readonly property string overrideColorMode: barConfig?.shadowColorMode ?? "default"
readonly property color overrideBaseColor: {
switch (overrideColorMode) {
readonly property real shadowIntensity: barConfig?.shadowIntensity ?? 0
readonly property bool shadowEnabled: shadowIntensity > 0
readonly property int blurMax: 64
readonly property real shadowBlurPx: shadowIntensity * 0.2
readonly property real shadowBlur: Math.max(0, Math.min(1, shadowBlurPx / blurMax))
readonly property real shadowOpacity: (barConfig?.shadowOpacity ?? 60) / 100
readonly property string shadowColorMode: barConfig?.shadowColorMode ?? "text"
readonly property color shadowBaseColor: {
switch (shadowColorMode) {
case "surface":
return Theme.surface;
case "primary":
@@ -98,16 +71,10 @@ Item {
case "custom":
return barConfig?.shadowCustomColor ?? "#000000";
default:
return "#000000";
return Theme.surfaceText;
}
}
// Resolved values — per-bar override wins if set, otherwise use global M3 elevation
readonly property real shadowBlurPx: hasPerBarOverride ? overrideBlurPx : (elevLevel.blurPx ?? 8)
readonly property color shadowColor: hasPerBarOverride ? Theme.withAlpha(overrideBaseColor, overrideOpacity) : Theme.elevationShadowColor(elevLevel)
readonly property real shadowOffsetMagnitude: hasPerBarOverride ? (overrideBlurPx * 0.5) : Theme.elevationOffsetMagnitude(elevLevel, 4, effectiveShadowDirection)
readonly property real shadowOffsetX: Theme.elevationOffsetXFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude)
readonly property real shadowOffsetY: Theme.elevationOffsetYFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude)
readonly property color shadowColor: Theme.withAlpha(shadowBaseColor, shadowOpacity * barWindow._backgroundAlpha)
readonly property string mainPath: generatePathForPosition(width, height)
readonly property string borderFullPath: generateBorderFullPath(width, height)
@@ -151,28 +118,42 @@ Item {
}
}
ElevationShadow {
id: barShadow
visible: root.shadowEnabled && root.width > 0 && root.height > 0
Loader {
id: shadowLoader
anchors.fill: parent
active: root.shadowEnabled && mainPathCorrectShape
asynchronous: false
sourceComponent: Item {
anchors.fill: parent
// Size to the bar's rectangular body, excluding gothic wing extensions
x: root.isRight ? root.wing : 0
y: root.isBottom ? root.wing : 0
width: axis.isVertical ? (parent.width - root.wing) : parent.width
height: axis.isVertical ? parent.height : (parent.height - root.wing)
layer.enabled: true
layer.smooth: true
layer.samples: 8
layer.textureSize: Qt.size(Math.round(width * barWindow._dpr * 2), Math.round(height * barWindow._dpr * 2))
layer.effect: MultiEffect {
shadowEnabled: true
shadowBlur: root.shadowBlur
shadowColor: root.shadowColor
shadowVerticalOffset: root.isTop ? root.shadowBlurPx * 0.5 : (root.isBottom ? -root.shadowBlurPx * 0.5 : 0)
shadowHorizontalOffset: root.isLeft ? root.shadowBlurPx * 0.5 : (root.isRight ? -root.shadowBlurPx * 0.5 : 0)
autoPaddingEnabled: true
}
shadowEnabled: root.shadowEnabled
level: root.hasPerBarOverride ? null : root.elevLevel
direction: root.effectiveShadowDirection
fallbackOffset: 4
targetRadius: root.rt
targetColor: barWindow._bgColor
Shape {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
shadowBlurPx: root.shadowBlurPx
shadowOffsetX: root.shadowOffsetX
shadowOffsetY: root.shadowOffsetY
shadowColor: root.shadowColor
blurMax: Theme.elevationBlurMax
ShapePath {
fillColor: barWindow._bgColor
strokeColor: "transparent"
strokeWidth: 0
PathSvg {
path: root.mainPath
}
}
}
}
}
Loader {

View File

@@ -140,20 +140,6 @@ PanelWindow {
}
readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen)
// Shadow buffer: extra window space for shadow to render beyond bar bounds
readonly property bool _shadowActive: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || (barConfig?.shadowIntensity ?? 0) > 0
readonly property real _shadowBuffer: {
if (!_shadowActive)
return 0;
const hasOverride = (barConfig?.shadowIntensity ?? 0) > 0;
if (hasOverride) {
const blur = (barConfig.shadowIntensity ?? 0) * 0.2;
const offset = blur * 0.5;
return Theme.snap(Math.max(16, blur + offset + 8), _dpr);
}
return Theme.snap(Theme.elevationRenderPadding(Theme.elevationLevel2, "top", 4, 8, 16), _dpr);
}
property string screenName: modelData.name
property bool hasMaximizedToplevel: false
@@ -368,8 +354,8 @@ PanelWindow {
}
screen: modelData
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) + _shadowBuffer : 0
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) + _shadowBuffer : 0
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) : 0
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + effectiveSpacing + ((barConfig?.gothCornersEnabled ?? false) && !hasMaximizedToplevel ? _wingR : 0), _dpr) : 0
color: "transparent"
property var nativeInhibitor: null
@@ -638,7 +624,7 @@ PanelWindow {
Item {
id: topBarCore
anchors.fill: parent
layer.enabled: false
layer.enabled: true
property bool autoHide: barConfig?.autoHide ?? false
property bool revealSticky: false

View File

@@ -167,22 +167,9 @@ DankPopout {
}
Column {
id: headerInfoColumn
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
width: parent.width - Theme.iconSizeLarge - 32 - Theme.spacingM * 2
readonly property string timeInfoText: {
if (!BatteryService.batteryAvailable)
return "Power profile management available";
const time = BatteryService.formatTimeRemaining();
if (time !== "Unknown") {
return BatteryService.isCharging ? `Time until full: ${time}` : `Time remaining: ${time}`;
}
return "";
}
readonly property bool showPowerRate: BatteryService.batteryAvailable && Math.abs(BatteryService.changeRate) > 0.05
readonly property bool isOnAC: BatteryService.batteryAvailable && (BatteryService.isCharging || BatteryService.isPluggedIn)
readonly property bool isDischarging: BatteryService.batteryAvailable && !BatteryService.isCharging && !BatteryService.isPluggedIn
Row {
spacing: Theme.spacingS
@@ -220,35 +207,21 @@ DankPopout {
}
}
Row {
width: parent.width
spacing: Theme.spacingS
visible: headerInfoColumn.timeInfoText.length > 0
StyledText {
id: powerRateText
text: `${headerInfoColumn.isOnAC ? "+" : (headerInfoColumn.isDischarging ? "-" : "")}${Math.abs(BatteryService.changeRate).toFixed(1)}W`
font.pixelSize: Theme.fontSizeSmall
color: {
if (headerInfoColumn.isOnAC) {
return Theme.primary;
}
if (headerInfoColumn.isDischarging) {
return Theme.warning;
}
return Theme.surfaceTextMedium;
StyledText {
text: {
if (!BatteryService.batteryAvailable)
return "Power profile management available";
const time = BatteryService.formatTimeRemaining();
if (time !== "Unknown") {
return BatteryService.isCharging ? `Time until full: ${time}` : `Time remaining: ${time}`;
}
font.weight: Font.Medium
visible: headerInfoColumn.showPowerRate
}
StyledText {
text: headerInfoColumn.timeInfoText
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
elide: Text.ElideRight
width: parent.width - (powerRateText.visible ? (powerRateText.implicitWidth + parent.spacing) : 0)
return "";
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
visible: text.length > 0
elide: Text.ElideRight
width: parent.width
}
}

View File

@@ -29,21 +29,12 @@ Loader {
readonly property bool orientationMatches: (axis?.isVertical ?? false) === isInColumn
readonly property bool widgetEnabled: widgetData?.enabled !== false
active: orientationMatches && getWidgetVisible(widgetId, DgopService.dgopAvailable) && (widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: getWidgetComponent(widgetId, components)
opacity: getWidgetEnabled(widgetData?.enabled) ? 1 : 0
signal contentItemReady(var item)
Binding {
target: root.item
when: root.item && !root.widgetEnabled
property: "visible"
value: false
restoreMode: Binding.RestoreBinding
}
Binding {
target: root.item
when: root.item && "parentScreen" in root.item
@@ -278,4 +269,8 @@ Loader {
return widgetVisibility[widgetId] ?? true;
}
function getWidgetEnabled(enabled) {
return enabled !== false;
}
}

View File

@@ -9,7 +9,6 @@ BasePill {
property var widgetData: null
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
property int diskUsageMode: (widgetData && widgetData.diskUsageMode !== undefined) ? widgetData.diskUsageMode : 0
property bool isHovered: mouseArea.containsMouse
property bool isAutoHideBar: false
@@ -131,13 +130,7 @@ BasePill {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--";
}
if (!root.selectedMount) return "--";
switch (root.diskUsageMode) {
case 1: return root.selectedMount.size || "--";
case 2: return root.selectedMount.avail || "--";
case 3: return (root.selectedMount.avail || "--") + " / " + (root.selectedMount.size || "--");
default: return root.diskUsagePercent.toFixed(0);
}
return root.diskUsagePercent.toFixed(0);
}
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
color: Theme.widgetTextColor
@@ -185,13 +178,7 @@ BasePill {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--%";
}
if (!root.selectedMount) return "--%";
switch (root.diskUsageMode) {
case 1: return root.selectedMount.size || "--";
case 2: return root.selectedMount.avail || "--";
case 3: return (root.selectedMount.avail || "--") + " / " + (root.selectedMount.size || "--");
default: return root.diskUsagePercent.toFixed(0) + "%";
}
return root.diskUsagePercent.toFixed(0) + "%";
}
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
color: Theme.widgetTextColor
@@ -202,14 +189,7 @@ BasePill {
StyledTextMetrics {
id: diskBaseline
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
text: {
switch (root.diskUsageMode) {
case 3: return "888.8G / 888.8G";
case 1:
case 2: return "888.8G";
default: return "100%";
}
}
text: "100%"
}
width: Math.max(diskBaseline.width, paintedWidth)

View File

@@ -178,9 +178,8 @@ BasePill {
if (root.popoutTarget && root.popoutTarget.setTriggerPosition) {
const globalPos = parent.mapToItem(null, 0, 0);
const currentScreen = root.parentScreen || Screen;
const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width, root.barSpacing, barPosition, root.barConfig);
root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig);
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width);
root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen);
}
root.clicked();
}
@@ -335,9 +334,8 @@ BasePill {
if (root.popoutTarget && root.popoutTarget.setTriggerPosition) {
const globalPos = mapToItem(null, 0, 0);
const currentScreen = root.parentScreen || Screen;
const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.width, root.barSpacing, barPosition, root.barConfig);
root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig);
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.width);
root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen);
}
root.clicked();
}

View File

@@ -14,7 +14,6 @@ BasePill {
property var widgetData: null
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false
property bool showInGb: (widgetData && widgetData.showInGb !== undefined) ? widgetData.showInGb : false
readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0
signal ramClicked
@@ -60,10 +59,6 @@ BasePill {
return "--";
}
if (root.showInGb) {
return (DgopService.usedMemoryMB / 1024).toFixed(1);
}
return DgopService.memoryUsage.toFixed(0);
}
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
@@ -118,14 +113,13 @@ BasePill {
id: ramBaseline
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
text: {
let baseText = root.showInGb ? "88.8 GB" : "88%";
if (!root.showSwap) {
return baseText;
return "88%";
}
if (root.swapUsage < 10) {
return baseText + " · 0%";
return "88% · 0%";
}
return baseText + " · 88%";
return "88% · 88%";
}
}
@@ -133,16 +127,10 @@ BasePill {
id: ramText
text: {
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
return root.showInGb ? "-- GB" : "--%";
}
let ramText = "";
if (root.showInGb) {
ramText = (DgopService.usedMemoryMB / 1024).toFixed(1) + " GB";
} else {
ramText = DgopService.memoryUsage.toFixed(0) + "%";
return "--%";
}
let ramText = DgopService.memoryUsage.toFixed(0) + "%";
if (root.showSwap && DgopService.totalSwapKB > 0) {
return ramText + " · " + root.swapUsage.toFixed(0) + "%";
}

View File

@@ -41,12 +41,6 @@ BasePill {
return `${id}::${tooltipTitle}`;
}
// ! TODO - replace with either native dbus client (like plugins use) or just a DMS cli or something
function callContextMenuFallback(trayItemId, globalX, globalY) {
const script = ['ITEMS=$(dbus-send --session --print-reply --dest=org.kde.StatusNotifierWatcher /StatusNotifierWatcher org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierWatcher string:RegisteredStatusNotifierItems 2>/dev/null)', 'while IFS= read -r line; do', ' line="${line#*\\\"}"', ' line="${line%\\\"*}"', ' [ -z "$line" ] && continue', ' BUS="${line%%/*}"', ' OBJ="/${line#*/}"', ' ID=$(dbus-send --session --print-reply --dest="$BUS" "$OBJ" org.freedesktop.DBus.Properties.Get string:org.kde.StatusNotifierItem string:Id 2>/dev/null | grep -oP "(?<=\\\")(.*?)(?=\\\")" | tail -1)', ' if [ "$ID" = "$1" ]; then', ' dbus-send --session --type=method_call --dest="$BUS" "$OBJ" org.kde.StatusNotifierItem.ContextMenu int32:"$2" int32:"$3"', ' exit 0', ' fi', 'done <<< "$ITEMS"',].join("\n");
Quickshell.execDetached(["bash", "-c", script, "_", trayItemId, String(globalX), String(globalY)]);
}
property int _trayOrderTrigger: 0
Connections {
@@ -386,11 +380,8 @@ BasePill {
return;
if (mouse.button !== Qt.RightButton)
return;
if (!delegateRoot.trayItem?.hasMenu) {
const gp = trayItemArea.mapToGlobal(mouse.x, mouse.y);
root.callContextMenuFallback(delegateRoot.trayItem.id, Math.round(gp.x), Math.round(gp.y));
if (!delegateRoot.trayItem?.hasMenu)
return;
}
root.menuOpen = false;
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
}
@@ -646,11 +637,8 @@ BasePill {
return;
if (mouse.button !== Qt.RightButton)
return;
if (!delegateRoot.trayItem?.hasMenu) {
const gp = trayItemArea.mapToGlobal(mouse.x, mouse.y);
root.callContextMenuFallback(delegateRoot.trayItem.id, Math.round(gp.x), Math.round(gp.y));
if (!delegateRoot.trayItem?.hasMenu)
return;
}
root.menuOpen = false;
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
}
@@ -940,10 +928,9 @@ BasePill {
}
})(), overflowMenu.dpr)
readonly property var elev: Theme.elevationLevel2
property real shadowBlurPx: elev && elev.blurPx !== undefined ? elev.blurPx : 8
property real shadowSpreadPx: elev && elev.spreadPx !== undefined ? elev.spreadPx : 0
property real shadowBaseAlpha: elev && elev.alpha !== undefined ? elev.alpha : 0.25
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: Theme.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
@@ -964,26 +951,37 @@ BasePill {
}
}
ElevationShadow {
Item {
id: bgShadowLayer
anchors.fill: parent
level: menuContainer.elev
fallbackOffset: 4
shadowBlurPx: menuContainer.shadowBlurPx
shadowSpreadPx: menuContainer.shadowSpreadPx
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha);
}
targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
targetRadius: Theme.cornerRadius
sourceRect.antialiasing: true
sourceRect.smooth: true
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.smooth: true
layer.textureSize: Qt.size(Math.round(width * overflowMenu.dpr * 2), Math.round(height * overflowMenu.dpr * 2))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
layer.samples: 4
readonly property int blurMax: 64
layer.effect: MultiEffect {
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, menuContainer.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * menuContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha);
}
}
Rectangle {
anchors.fill: parent
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
antialiasing: true
smooth: true
}
}
Grid {
@@ -1067,11 +1065,9 @@ BasePill {
root.menuOpen = false;
return;
}
if (!trayItem.hasMenu) {
const gp = itemArea.mapToGlobal(mouse.x, mouse.y);
root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y));
if (!trayItem.hasMenu)
return;
}
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
}
}
@@ -1402,10 +1398,9 @@ BasePill {
}
})(), menuWindow.dpr)
readonly property var elev: Theme.elevationLevel2
property real shadowBlurPx: elev && elev.blurPx !== undefined ? elev.blurPx : 8
property real shadowSpreadPx: elev && elev.spreadPx !== undefined ? elev.spreadPx : 0
property real shadowBaseAlpha: elev && elev.alpha !== undefined ? elev.alpha : 0.25
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: Theme.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
@@ -1426,24 +1421,35 @@ BasePill {
}
}
ElevationShadow {
Item {
id: menuBgShadowLayer
anchors.fill: parent
level: menuContainer.elev
fallbackOffset: 4
shadowBlurPx: menuContainer.shadowBlurPx
shadowSpreadPx: menuContainer.shadowSpreadPx
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha);
}
targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
targetRadius: Theme.cornerRadius
sourceRect.antialiasing: true
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.smooth: true
layer.textureSize: Qt.size(Math.round(width * menuWindow.dpr), Math.round(height * menuWindow.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, menuContainer.shadowBlurPx / menuBgShadowLayer.blurMax))
shadowScale: 1 + (2 * menuContainer.shadowSpreadPx) / Math.max(1, Math.min(menuBgShadowLayer.width, menuBgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha);
}
}
Rectangle {
anchors.fill: parent
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
antialiasing: true
}
}
QsMenuAnchor {

View File

@@ -177,9 +177,8 @@ BasePill {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToItem(null, 0, 0);
const currentScreen = parentScreen || Screen;
const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig);
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig);
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth);
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen);
}
root.clicked();
}

View File

@@ -89,18 +89,14 @@ Item {
}
}
ElevationShadow {
id: volumeShadowLayer
anchors.fill: parent
z: -1
level: Theme.elevationLevel2
fallbackOffset: 4
targetRadius: volumePanel.radius
targetColor: volumePanel.color
borderColor: volumePanel.border.color
borderWidth: volumePanel.border.width
shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 8
shadowBlur: 1.0
shadowColor: Qt.rgba(0, 0, 0, 0.4)
shadowOpacity: 0.7
}
MouseArea {
@@ -227,18 +223,14 @@ Item {
}
}
ElevationShadow {
id: audioDevicesShadowLayer
anchors.fill: parent
z: -1
level: Theme.elevationLevel2
fallbackOffset: 4
targetRadius: audioDevicesPanel.radius
targetColor: audioDevicesPanel.color
borderColor: audioDevicesPanel.border.color
borderWidth: audioDevicesPanel.border.width
shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 8
shadowBlur: 1.0
shadowColor: Qt.rgba(0, 0, 0, 0.4)
shadowOpacity: 0.7
}
Column {
@@ -381,18 +373,14 @@ Item {
}
}
ElevationShadow {
id: playersShadowLayer
anchors.fill: parent
z: -1
level: Theme.elevationLevel2
fallbackOffset: 4
targetRadius: playersPanel.radius
targetColor: playersPanel.color
borderColor: playersPanel.border.color
borderWidth: playersPanel.border.width
shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 8
shadowBlur: 1.0
shadowColor: Qt.rgba(0, 0, 0, 0.4)
shadowOpacity: 0.7
}
Column {

View File

@@ -529,15 +529,14 @@ Item {
onClicked: activePlayer && activePlayer.togglePlaying()
}
ElevationShadow {
anchors.fill: parent
z: -1
level: Theme.elevationLevel1
fallbackOffset: 1
targetRadius: parent.radius
targetColor: parent.color
shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 0
shadowBlur: 1.0
shadowColor: Qt.rgba(0, 0, 0, 0.3)
shadowOpacity: 0.3
}
}
}

View File

@@ -241,15 +241,14 @@ Item {
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
layer.enabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: Theme.elevationEnabled
shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1)
shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1)
shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0
blurMax: Theme.elevationBlurMax
shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1)
shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.8
shadowColor: Qt.rgba(0, 0, 0, 0.2)
shadowOpacity: 0.2
}
}
@@ -813,14 +812,14 @@ Item {
x: (pos?.h ?? 0) * skyBox.effectiveWidth - (moonPhase.width / 2) + skyBox.hMargin
y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (moonPhase.height / 2) + skyBox.vMargin
layer.enabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: Theme.elevationEnabled
shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2)
shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4)
shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0
blurMax: Theme.elevationBlurMax
shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2)
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.8
shadowColor: Qt.rgba(0, 0, 0, 0.2)
shadowOpacity: 0.2
}
}
@@ -835,14 +834,14 @@ Item {
x: (pos?.h ?? 0) * skyBox.effectiveWidth - (sun.width / 2) + skyBox.hMargin
y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (sun.height / 2) + skyBox.vMargin
layer.enabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: Theme.elevationEnabled
shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2)
shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4)
shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0
blurMax: Theme.elevationBlurMax
shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2)
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.8
shadowColor: Qt.rgba(0, 0, 0, 0.2)
shadowOpacity: 0.2
}
}
}

View File

@@ -41,11 +41,6 @@ Singleton {
property string lockDateFormat: ""
property bool lockScreenShowPowerActions: true
property bool lockScreenShowProfileImage: true
property bool powerActionConfirm: true
property real powerActionHoldDuration: 0.5
property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]
property string powerMenuDefaultAction: "logout"
property bool powerMenuGridLayout: false
property var screenPreferences: ({})
property int animationSpeed: 2
property string wallpaperFillMode: "Fill"
@@ -80,11 +75,6 @@ Singleton {
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : "";
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true;
lockScreenShowProfileImage = settings.lockScreenShowProfileImage !== undefined ? settings.lockScreenShowProfileImage : true;
powerActionConfirm = settings.powerActionConfirm !== undefined ? settings.powerActionConfirm : true;
powerActionHoldDuration = settings.powerActionHoldDuration !== undefined ? settings.powerActionHoldDuration : 0.5;
powerMenuActions = settings.powerMenuActions !== undefined ? settings.powerMenuActions : ["reboot", "logout", "poweroff", "lock", "suspend", "restart"];
powerMenuDefaultAction = settings.powerMenuDefaultAction !== undefined ? settings.powerMenuDefaultAction : "logout";
powerMenuGridLayout = settings.powerMenuGridLayout !== undefined ? settings.powerMenuGridLayout : false;
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({});
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2;
wallpaperFillMode = settings.wallpaperFillMode !== undefined ? settings.wallpaperFillMode : "Fill";

View File

@@ -1231,12 +1231,6 @@ Item {
LockPowerMenu {
id: powerMenu
showLogout: false
powerActionConfirmOverride: GreetdSettings.powerActionConfirm
powerActionHoldDurationOverride: GreetdSettings.powerActionHoldDuration
powerMenuActionsOverride: GreetdSettings.powerMenuActions
powerMenuDefaultActionOverride: GreetdSettings.powerMenuDefaultAction
powerMenuGridLayoutOverride: GreetdSettings.powerMenuGridLayout
requiredActions: ["poweroff"]
onClosed: {
if (isPrimaryScreen && inputField && inputField.forceActiveFocus) {
Qt.callLater(() => inputField.forceActiveFocus());

View File

@@ -24,20 +24,13 @@ Rectangle {
property real holdProgress: 0
property bool showHoldHint: false
property var powerActionConfirmOverride: undefined
property var powerActionHoldDurationOverride: undefined
property var powerMenuActionsOverride: undefined
property var powerMenuDefaultActionOverride: undefined
property var powerMenuGridLayoutOverride: undefined
property var requiredActions: []
readonly property bool needsConfirmation: powerActionConfirmOverride !== undefined ? powerActionConfirmOverride : SettingsData.powerActionConfirm
readonly property int holdDurationMs: (powerActionHoldDurationOverride !== undefined ? powerActionHoldDurationOverride : SettingsData.powerActionHoldDuration) * 1000
readonly property bool needsConfirmation: SettingsData.powerActionConfirm
readonly property int holdDurationMs: SettingsData.powerActionHoldDuration * 1000
signal closed
function updateVisibleActions() {
const allActions = powerMenuActionsOverride !== undefined ? powerMenuActionsOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"]);
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"];
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false;
let filtered = allActions.filter(action => {
if (action === "hibernate" && !hibernateSupported)
@@ -51,14 +44,9 @@ Rectangle {
return true;
});
for (const action of requiredActions) {
if (!filtered.includes(action))
filtered.push(action);
}
visibleActions = filtered;
useGridLayout = powerMenuGridLayoutOverride !== undefined ? powerMenuGridLayoutOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false);
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false;
if (!useGridLayout)
return;
const count = visibleActions.length;
@@ -85,7 +73,7 @@ Rectangle {
}
function getDefaultActionIndex() {
const defaultAction = powerMenuDefaultActionOverride !== undefined ? powerMenuDefaultActionOverride : ((typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend");
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend";
const index = visibleActions.indexOf(defaultAction);
return index >= 0 ? index : 0;
}
@@ -792,9 +780,8 @@ Rectangle {
}
StyledText {
readonly property real totalMs: root.holdDurationMs
readonly property real totalMs: SettingsData.powerActionHoldDuration * 1000
readonly property int remainingMs: Math.ceil(totalMs * (1 - root.holdProgress))
readonly property real durationSec: root.holdDurationMs / 1000
text: {
if (root.showHoldHint)
return I18n.tr("Hold longer to confirm");
@@ -805,7 +792,7 @@ Rectangle {
}
if (totalMs < 1000)
return I18n.tr("Hold to confirm (%1 ms)").arg(totalMs);
return I18n.tr("Hold to confirm (%1s)").arg(durationSec);
return I18n.tr("Hold to confirm (%1s)").arg(SettingsData.powerActionHoldDuration);
}
font.pixelSize: Theme.fontSizeSmall
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import qs.Common
import qs.Services
@@ -31,21 +30,7 @@ Rectangle {
width: parent ? parent.width : 400
height: baseCardHeight + contentItem.extraHeight
radius: Theme.cornerRadius
clip: false
readonly property bool shadowsAllowed: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
ElevationShadow {
id: shadowLayer
anchors.fill: parent
z: -1
level: Theme.elevationLevel1
fallbackOffset: 1
targetRadius: root.radius
targetColor: root.color
borderColor: root.border.color
borderWidth: root.border.width
shadowEnabled: root.shadowsAllowed
}
clip: true
color: {
if (isSelected && keyboardNavigationActive)
@@ -64,7 +49,7 @@ Rectangle {
return 1.5;
if (historyItem.urgency === 2)
return 2;
return 0;
return 1;
}
Behavior on border.color {

View File

@@ -232,11 +232,6 @@ Item {
height: parent.height - filterChips.height - Theme.spacingS
clip: true
spacing: Theme.spacingS
readonly property real horizontalShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1)
readonly property real verticalShadowGutter: Theme.snap(Math.max(Theme.spacingS, 8), 1)
readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1)
topMargin: verticalShadowGutter
bottomMargin: verticalShadowGutter
model: ScriptModel {
id: historyModel
@@ -268,14 +263,13 @@ Item {
}
width: ListView.view.width
height: historyCard.height + historyListView.delegateShadowGutter
clip: false
height: historyCard.height
clip: true
HistoryNotificationCard {
id: historyCard
width: Math.max(0, parent.width - (historyListView.horizontalShadowGutter * 2))
y: historyListView.delegateShadowGutter / 2
x: historyListView.horizontalShadowGutter + delegateRoot.swipeOffset
width: parent.width
x: delegateRoot.swipeOffset
historyItem: modelData
isSelected: root.keyboardActive && root.selectedIndex === index
keyboardNavigationActive: root.keyboardActive

View File

@@ -18,10 +18,6 @@ DankListView {
property real swipingCardOffset: 0
property real __pendingStableHeight: 0
property real __heightUpdateThreshold: 20
readonly property real shadowBlurPx: Theme.elevationEnabled ? ((Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined) ? Theme.elevationLevel1.blurPx : 4) : 0
readonly property real shadowHorizontalGutter: Theme.snap(Math.max(Theme.spacingS, Math.min(32, shadowBlurPx * 1.5 + 6)), 1)
readonly property real shadowVerticalGutter: Theme.snap(Math.max(Theme.spacingXS, 6), 1)
readonly property real delegateShadowGutter: Theme.snap(Math.max(Theme.spacingXS, 4), 1)
Component.onCompleted: {
Qt.callLater(() => {
@@ -60,26 +56,21 @@ DankListView {
let delta = 0;
for (let i = 0; i < count; i++) {
const item = itemAtIndex(i);
if (item && item.children[0] && item.children[0].isAnimating) {
const targetDelegateHeight = item.children[0].targetHeight + listView.delegateShadowGutter;
delta += targetDelegateHeight - item.height;
}
if (item && item.children[0] && item.children[0].isAnimating)
delta += item.children[0].targetHeight - item.height;
}
const targetHeight = contentHeight + delta;
// During expansion, always update immediately without threshold check
stableContentHeight = targetHeight;
} else {
__pendingStableHeight = contentHeight;
heightUpdateDebounce.stop();
stableContentHeight = __pendingStableHeight;
heightUpdateDebounce.restart();
}
}
clip: true
model: NotificationService.groupedNotifications
spacing: Theme.spacingL
topMargin: shadowVerticalGutter
bottomMargin: shadowVerticalGutter
onIsUserScrollingChanged: {
if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) {
@@ -143,7 +134,8 @@ DankListView {
readonly property real dismissThreshold: width * 0.35
property bool __delegateInitialized: false
readonly property bool isAdjacentToSwipe: listView.count >= 2 && listView.swipingCardIndex !== -1 && (index === listView.swipingCardIndex - 1 || index === listView.swipingCardIndex + 1)
readonly property bool isAdjacentToSwipe: listView.count >= 2 && listView.swipingCardIndex !== -1 &&
(index === listView.swipingCardIndex - 1 || index === listView.swipingCardIndex + 1)
readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? listView.swipingCardOffset * 0.10 : 0
readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(listView.swipingCardOffset) / width * 0.02 : 1.0
readonly property real swipeFadeStartOffset: width * 0.75
@@ -157,14 +149,13 @@ DankListView {
}
width: ListView.view.width
height: notificationCard.height + listView.delegateShadowGutter
clip: false
height: notificationCard.height
clip: notificationCard.isAnimating
NotificationCard {
id: notificationCard
width: Math.max(0, parent.width - (listView.shadowHorizontalGutter * 2))
y: listView.delegateShadowGutter / 2
x: listView.shadowHorizontalGutter + delegateRoot.swipeOffset + delegateRoot.adjacentSwipeInfluence
width: parent.width
x: delegateRoot.swipeOffset + delegateRoot.adjacentSwipeInfluence
listLevelAdjacentScaleInfluence: delegateRoot.adjacentScaleInfluence
listLevelScaleAnimationsEnabled: listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe
notificationGroup: modelData

View File

@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Services.Notifications
import qs.Common
@@ -39,14 +38,7 @@ Rectangle {
height: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight)
readonly property real targetHeight: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight)
radius: Theme.cornerRadius
scale: (cardHoverHandler.hovered ? 1.004 : 1.0) * listLevelAdjacentScaleInfluence
readonly property bool shadowsAllowed: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
readonly property var shadowElevation: Theme.elevationLevel1
readonly property real baseShadowBlurPx: (shadowElevation && shadowElevation.blurPx !== undefined) ? shadowElevation.blurPx : 4
readonly property real hoverShadowBlurBoost: cardHoverHandler.hovered ? Math.min(2, baseShadowBlurPx * 0.25) : 0
property real shadowBlurPx: shadowsAllowed ? (baseShadowBlurPx + hoverShadowBlurBoost) : 0
property real shadowOffsetXPx: shadowsAllowed ? Theme.elevationOffsetX(shadowElevation) : 0
property real shadowOffsetYPx: shadowsAllowed ? (Theme.elevationOffsetY(shadowElevation, 1) + (cardHoverHandler.hovered ? 0.35 : 0)) : 0
scale: (cardHoverHandler.hovered ? 1.01 : 1.0) * listLevelAdjacentScaleInfluence
property bool __initialized: false
Component.onCompleted: {
@@ -64,27 +56,6 @@ Rectangle {
}
}
Behavior on shadowBlurPx {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on shadowOffsetXPx {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on shadowOffsetYPx {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on border.color {
enabled: root.__initialized
ColorAnimation {
@@ -124,31 +95,14 @@ Rectangle {
if (notificationGroup?.latestNotification?.urgency === NotificationUrgency.Critical) {
return 2;
}
return 0;
return 1;
}
clip: false
clip: true
HoverHandler {
id: cardHoverHandler
}
ElevationShadow {
id: shadowLayer
anchors.fill: parent
z: -1
level: root.shadowElevation
targetRadius: root.radius
targetColor: root.color
borderColor: root.border.color
borderWidth: root.border.width
shadowBlurPx: root.shadowBlurPx
shadowSpreadPx: 0
shadowOffsetX: root.shadowOffsetXPx
shadowOffsetY: root.shadowOffsetYPx
shadowColor: root.shadowElevation ? Theme.elevationShadowColor(root.shadowElevation) : "transparent"
shadowEnabled: root.shadowsAllowed
}
Rectangle {
anchors.fill: parent
radius: parent.radius
@@ -350,13 +304,8 @@ Rectangle {
onClicked: mouse => {
if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) {
root.userInitiatedExpansion = true;
const messageId = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : "";
NotificationService.toggleMessageExpansion(messageId);
Qt.callLater(() => {
if (root && !root.isAnimating)
root.userInitiatedExpansion = false;
});
}
}
@@ -470,7 +419,9 @@ Rectangle {
id: delegateRect
width: parent.width
readonly property bool isAdjacentToSwipe: root.swipingNotificationIndex !== -1 && (expandedDelegateWrapper.index === root.swipingNotificationIndex - 1 || expandedDelegateWrapper.index === root.swipingNotificationIndex + 1)
readonly property bool isAdjacentToSwipe: root.swipingNotificationIndex !== -1 &&
(expandedDelegateWrapper.index === root.swipingNotificationIndex - 1 ||
expandedDelegateWrapper.index === root.swipingNotificationIndex + 1)
readonly property real adjacentSwipeInfluence: isAdjacentToSwipe ? root.swipingNotificationOffset * 0.10 : 0
readonly property real adjacentScaleInfluence: isAdjacentToSwipe ? 1.0 - Math.abs(root.swipingNotificationOffset) / width * 0.02 : 1.0
@@ -654,12 +605,7 @@ Rectangle {
onClicked: mouse => {
if (!parent.hoveredLink && (bodyText.hasMoreText || messageExpanded)) {
root.userInitiatedExpansion = true;
NotificationService.toggleMessageExpansion(modelData?.notification?.id || "");
Qt.callLater(() => {
if (root && !root.isAnimating)
root.userInitiatedExpansion = false;
});
}
}

View File

@@ -7,22 +7,15 @@ DankPopout {
id: root
layerNamespace: "dms:notification-center-popout"
fullHeightSurface: false
fullHeightSurface: true
property bool notificationHistoryVisible: false
property var triggerScreen: null
property real stablePopupHeight: 400
property real _lastAlignedContentHeight: -1
property bool _pendingSizedOpen: false
function updateStablePopupHeight() {
const item = contentLoader.item;
if (item && !root.shouldBeVisible) {
const notificationList = findChild(item, "notificationList");
if (notificationList && typeof notificationList.forceLayout === "function") {
notificationList.forceLayout();
}
}
const target = item ? Theme.px(item.implicitHeight, dpr) : 400;
if (Math.abs(target - _lastAlignedContentHeight) < 0.5)
return;
@@ -33,7 +26,7 @@ DankPopout {
NotificationKeyboardController {
id: keyboardController
listView: null
isOpen: root.shouldBeVisible
isOpen: notificationHistoryVisible
onClose: () => {
notificationHistoryVisible = false;
}
@@ -47,42 +40,20 @@ DankPopout {
suspendShadowWhileResizing: false
screen: triggerScreen
shouldBeVisible: notificationHistoryVisible
function toggle() {
notificationHistoryVisible = !notificationHistoryVisible;
}
function openSized() {
if (!notificationHistoryVisible)
return;
primeContent();
if (contentLoader.item) {
updateStablePopupHeight();
_pendingSizedOpen = false;
Qt.callLater(() => {
if (!notificationHistoryVisible)
return;
updateStablePopupHeight();
open();
clearPrimedContent();
});
return;
}
_pendingSizedOpen = true;
}
onBackgroundClicked: {
notificationHistoryVisible = false;
}
onNotificationHistoryVisibleChanged: {
if (notificationHistoryVisible) {
openSized();
open();
} else {
_pendingSizedOpen = false;
clearPrimedContent();
close();
}
}
@@ -111,17 +82,6 @@ DankPopout {
target: contentLoader
function onLoaded() {
root.updateStablePopupHeight();
if (root._pendingSizedOpen && root.notificationHistoryVisible) {
Qt.callLater(() => {
if (!root._pendingSizedOpen || !root.notificationHistoryVisible)
return;
root.updateStablePopupHeight();
root._pendingSizedOpen = false;
root.open();
root.clearPrimedContent();
});
return;
}
if (root.shouldBeVisible)
Qt.callLater(root.setupKeyboardNavigation);
}
@@ -179,8 +139,7 @@ DankPopout {
baseHeight += Theme.spacingM * 2;
const settingsHeight = notificationSettings.expanded ? notificationSettings.contentHeight : 0;
const currentListHeight = root.shouldBeVisible ? notificationList.stableContentHeight : notificationList.listContentHeight;
let listHeight = notificationHeader.currentTab === 0 ? currentListHeight : Math.max(200, NotificationService.historyList.length * 80);
let listHeight = notificationHeader.currentTab === 0 ? notificationList.stableContentHeight : Math.max(200, NotificationService.historyList.length * 80);
if (notificationHeader.currentTab === 0 && NotificationService.groupedNotifications.length === 0) {
listHeight = 200;
}
@@ -274,21 +233,13 @@ DankPopout {
expanded: notificationHeader.showSettings
}
Item {
KeyboardNavigatedNotificationList {
id: notificationList
objectName: "notificationList"
visible: notificationHeader.currentTab === 0
width: parent.width
height: parent.height - notificationContent.cachedHeaderHeight - notificationSettings.height - contentColumnInner.spacing * 2
KeyboardNavigatedNotificationList {
id: notificationList
objectName: "notificationList"
anchors.fill: parent
anchors.leftMargin: -shadowHorizontalGutter
anchors.rightMargin: -shadowHorizontalGutter
anchors.topMargin: -(shadowVerticalGutter + delegateShadowGutter / 2)
anchors.bottomMargin: -(shadowVerticalGutter + delegateShadowGutter / 2)
cardAnimateExpansion: true
}
cardAnimateExpansion: true
}
HistoryNotificationList {

View File

@@ -118,8 +118,8 @@ PanelWindow {
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
readonly property real contentImplicitWidth: screen ? Math.min(400, Math.max(320, screen.width * 0.23)) : 380
readonly property real contentImplicitHeight: {
implicitWidth: screen ? Math.min(400, Math.max(320, screen.width * 0.23)) : 380
implicitHeight: {
if (SettingsData.notificationPopupPrivacyMode && !descriptionExpanded)
return basePopupHeightPrivacy;
if (!descriptionExpanded)
@@ -130,8 +130,6 @@ PanelWindow {
return basePopupHeight + bodyTextHeight - collapsedBodyHeight;
return basePopupHeight;
}
implicitWidth: contentImplicitWidth + (windowShadowPad * 2)
implicitHeight: contentImplicitHeight + (windowShadowPad * 2)
Behavior on implicitHeight {
enabled: !exiting && !_isDestroying
@@ -184,15 +182,11 @@ PanelWindow {
property bool isTopCenter: SettingsData.notificationPopupPosition === -1
property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter
property bool isCenterPosition: isTopCenter || isBottomCenter
readonly property real maxPopupShadowBlurPx: Math.max((Theme.elevationLevel3 && Theme.elevationLevel3.blurPx !== undefined) ? Theme.elevationLevel3.blurPx : 12, (Theme.elevationLevel4 && Theme.elevationLevel4.blurPx !== undefined) ? Theme.elevationLevel4.blurPx : 16)
readonly property real maxPopupShadowOffsetXPx: Math.max(Math.abs(Theme.elevationOffsetX(Theme.elevationLevel3)), Math.abs(Theme.elevationOffsetX(Theme.elevationLevel4)))
readonly property real maxPopupShadowOffsetYPx: Math.max(Math.abs(Theme.elevationOffsetY(Theme.elevationLevel3, 6)), Math.abs(Theme.elevationOffsetY(Theme.elevationLevel4, 8)))
readonly property real windowShadowPad: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled ? Theme.snap(Math.max(16, maxPopupShadowBlurPx + Math.max(maxPopupShadowOffsetXPx, maxPopupShadowOffsetYPx) + 8), dpr) : 0
anchors.top: true
anchors.left: true
anchors.bottom: false
anchors.right: false
anchors.bottom: true
anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
anchors.right: SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Right
mask: contentInputMask
@@ -211,10 +205,10 @@ PanelWindow {
}
margins {
top: getWindowTopMargin()
bottom: 0
left: getWindowLeftMargin()
right: 0
top: _storedTopMargin
bottom: _storedBottomMargin
left: getLeftMargin()
right: getRightMargin()
}
function getBarInfo() {
@@ -256,7 +250,7 @@ PanelWindow {
function getLeftMargin() {
if (isCenterPosition)
return screen ? (screen.width - alignedWidth) / 2 : 0;
return screen ? (screen.width - implicitWidth) / 2 : 0;
const popupPos = SettingsData.notificationPopupPosition;
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom;
@@ -280,56 +274,23 @@ PanelWindow {
return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance;
}
function getContentX() {
if (!screen)
return 0;
const popupPos = SettingsData.notificationPopupPosition;
const barLeft = getLeftMargin();
const barRight = getRightMargin();
if (isCenterPosition)
return Theme.snap((screen.width - alignedWidth) / 2, dpr);
if (popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom)
return Theme.snap(barLeft, dpr);
return Theme.snap(screen.width - alignedWidth - barRight, dpr);
}
function getContentY() {
if (!screen)
return 0;
const popupPos = SettingsData.notificationPopupPosition;
const barTop = getTopMargin();
const barBottom = getBottomMargin();
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left;
if (isTop)
return Theme.snap(barTop, dpr);
return Theme.snap(screen.height - alignedHeight - barBottom, dpr);
}
function getWindowLeftMargin() {
if (!screen)
return 0;
return Theme.snap(getContentX() - windowShadowPad, dpr);
}
function getWindowTopMargin() {
if (!screen)
return 0;
return Theme.snap(getContentY() - windowShadowPad, dpr);
}
readonly property bool screenValid: win.screen && !_isDestroying
readonly property real dpr: screenValid ? CompositorService.getScreenScale(win.screen) : 1
readonly property real alignedWidth: Theme.px(Math.max(0, implicitWidth - (windowShadowPad * 2)), dpr)
readonly property real alignedHeight: Theme.px(Math.max(0, implicitHeight - (windowShadowPad * 2)), dpr)
readonly property real alignedWidth: Theme.px(implicitWidth, dpr)
readonly property real alignedHeight: Theme.px(implicitHeight, dpr)
Item {
id: content
x: Theme.snap(windowShadowPad, dpr)
y: Theme.snap(windowShadowPad, dpr)
x: Theme.snap((win.width - alignedWidth) / 2, dpr)
y: {
const isTop = isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left;
if (isTop) {
return Theme.snap(screenY, dpr);
} else {
return Theme.snap(win.height - alignedHeight - screenY, dpr);
}
}
width: alignedWidth
height: alignedHeight
visible: !win._finalized
@@ -352,13 +313,12 @@ PanelWindow {
readonly property bool swipeActive: swipeDragHandler.active
property bool swipeDismissing: false
readonly property bool shadowsAllowed: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled
readonly property var elevLevel: cardHoverHandler.hovered ? Theme.elevationLevel4 : Theme.elevationLevel3
readonly property real cardInset: Theme.snap(4, win.dpr)
readonly property real shadowRenderPadding: shadowsAllowed ? Theme.snap(Math.max(16, shadowBlurPx + Math.max(Math.abs(shadowOffsetX), Math.abs(shadowOffsetY)) + 8), win.dpr) : 0
property real shadowBlurPx: shadowsAllowed ? (elevLevel && elevLevel.blurPx !== undefined ? elevLevel.blurPx : 12) : 0
property real shadowOffsetX: shadowsAllowed ? Theme.elevationOffsetX(elevLevel) : 0
property real shadowOffsetY: shadowsAllowed ? Theme.elevationOffsetY(elevLevel, 6) : 0
readonly property real radiusForShadow: Theme.cornerRadius
property real shadowBlurPx: SettingsData.notificationPopupShadowEnabled ? ((2 + radiusForShadow * 0.2) * (cardHoverHandler.hovered ? 1.2 : 1)) : 0
property real shadowSpreadPx: SettingsData.notificationPopupShadowEnabled ? (radiusForShadow * (cardHoverHandler.hovered ? 0.06 : 0)) : 0
property real shadowBaseAlpha: 0.35
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
Behavior on shadowBlurPx {
NumberAnimation {
@@ -367,50 +327,50 @@ PanelWindow {
}
}
Behavior on shadowOffsetX {
Behavior on shadowSpreadPx {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on shadowOffsetY {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
ElevationShadow {
Item {
id: bgShadowLayer
anchors.fill: parent
anchors.margins: -content.shadowRenderPadding
level: content.elevLevel
fallbackOffset: 6
shadowBlurPx: content.shadowBlurPx
shadowOffsetX: content.shadowOffsetX
shadowOffsetY: content.shadowOffsetY
shadowColor: content.shadowsAllowed && content.elevLevel ? Theme.elevationShadowColor(content.elevLevel) : "transparent"
shadowEnabled: !win._isDestroying && win.screenValid && content.shadowsAllowed
anchors.margins: Theme.snap(4, win.dpr)
layer.enabled: !win._isDestroying && win.screenValid
layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
sourceRect.anchors.fill: undefined
sourceRect.x: content.shadowRenderPadding + content.cardInset
sourceRect.y: content.shadowRenderPadding + content.cardInset
sourceRect.width: Math.max(0, content.width - (content.cardInset * 2))
sourceRect.height: Math.max(0, content.height - (content.cardInset * 2))
sourceRect.radius: Theme.cornerRadius
sourceRect.color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
sourceRect.border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.outline, 0.08)
sourceRect.border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: SettingsData.notificationPopupShadowEnabled
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, content.effectiveShadowAlpha);
}
}
Rectangle {
x: bgShadowLayer.sourceRect.x
y: bgShadowLayer.sourceRect.y
width: bgShadowLayer.sourceRect.width
height: bgShadowLayer.sourceRect.height
radius: bgShadowLayer.sourceRect.radius
id: shadowShapeSource
anchors.fill: parent
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.outline, 0.08)
border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
}
Rectangle {
anchors.fill: parent
radius: shadowShapeSource.radius
visible: notificationData && notificationData.urgency === NotificationUrgency.Critical
opacity: 1
clip: true
@@ -439,7 +399,7 @@ PanelWindow {
Item {
id: backgroundContainer
anchors.fill: parent
anchors.margins: content.cardInset
anchors.margins: Theme.snap(4, win.dpr)
clip: true
HoverHandler {

View File

@@ -351,7 +351,6 @@ Item {
Loader {
id: contentLoader
anchors.fill: parent
active: root.widgetEnabled && root.activeComponent !== null
sourceComponent: root.activeComponent
function reloadComponent() {

View File

@@ -878,17 +878,12 @@ Item {
x: hoveredButton ? hoveredButton.mapToItem(aboutTab, hoveredButton.width / 2, 0).x - width / 2 : 0
y: hoveredButton ? communityIcons.mapToItem(aboutTab, 0, 0).y - height - 8 : 0
ElevationShadow {
anchors.fill: parent
z: -1
level: Theme.elevationLevel1
fallbackOffset: 1
targetRadius: communityTooltip.radius
targetColor: communityTooltip.color
borderColor: communityTooltip.border.color
borderWidth: communityTooltip.border.width
shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowOpacity: 0.15
shadowVerticalOffset: 2
shadowBlur: 0.5
}
StyledText {

View File

@@ -52,11 +52,9 @@ Item {
}
function _isBarActive(c) {
if (!c.enabled)
return false;
if (!c.enabled) return false;
const prefs = c.screenPreferences || ["all"];
if (prefs.length > 0)
return true;
if (prefs.length > 0) return true;
return (c.showOnLastDisplay ?? true) && Quickshell.screens.length === 1;
}
@@ -66,8 +64,7 @@ Item {
return;
const hasHorizontal = configs.some(c => {
if (!_isBarActive(c))
return false;
if (!_isBarActive(c)) return false;
const p = c.position ?? SettingsData.Position.Top;
return p === SettingsData.Position.Top || p === SettingsData.Position.Bottom;
});
@@ -75,8 +72,7 @@ Item {
return;
const hasVertical = configs.some(c => {
if (!_isBarActive(c))
return false;
if (!_isBarActive(c)) return false;
const p = c.position ?? SettingsData.Position.Top;
return p === SettingsData.Position.Left || p === SettingsData.Position.Right;
});
@@ -140,9 +136,7 @@ Item {
scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace",
shadowIntensity: defaultBar.shadowIntensity ?? 0,
shadowOpacity: defaultBar.shadowOpacity ?? 60,
shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit",
shadowDirection: defaultBar.shadowDirection ?? "top",
shadowColorMode: defaultBar.shadowColorMode ?? "default",
shadowColorMode: defaultBar.shadowColorMode ?? "text",
shadowCustomColor: defaultBar.shadowCustomColor ?? "#000000"
};
SettingsData.addBarConfig(newBar);
@@ -1044,237 +1038,6 @@ Item {
}
}
SettingsCard {
id: shadowCard
iconName: "layers"
title: I18n.tr("Shadow Override", "bar shadow settings card")
settingKey: "barShadow"
collapsible: true
expanded: true
visible: selectedBarConfig?.enabled
readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0
readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "default") === "custom"
readonly property string directionSource: selectedBarConfig?.shadowDirectionMode ?? "inherit"
StyledText {
width: parent.width
text: I18n.tr("Enable a custom override below to set per-bar shadow intensity, opacity, and color.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignLeft
}
SettingsToggleRow {
text: I18n.tr("Custom Shadow Override")
description: I18n.tr("Override the global shadow with per-bar settings")
checked: shadowCard.shadowActive
onToggled: checked => {
if (checked) {
SettingsData.updateBarConfig(selectedBarId, {
shadowIntensity: 12,
shadowOpacity: 60
});
} else {
SettingsData.updateBarConfig(selectedBarId, {
shadowIntensity: 0
});
}
}
}
SettingsSliderRow {
visible: shadowCard.shadowActive
text: I18n.tr("Intensity", "shadow intensity slider")
minimum: 0
maximum: 100
unit: "px"
defaultValue: 12
value: selectedBarConfig?.shadowIntensity ?? 0
onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, {
shadowIntensity: newValue
})
}
SettingsSliderRow {
visible: shadowCard.shadowActive
text: I18n.tr("Opacity")
minimum: 10
maximum: 100
unit: "%"
defaultValue: 60
value: selectedBarConfig?.shadowOpacity ?? 60
onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, {
shadowOpacity: newValue
})
}
SettingsDropdownRow {
visible: shadowCard.shadowActive
text: I18n.tr("Direction Source", "bar shadow direction source")
description: I18n.tr("Choose how this bar resolves shadow direction")
settingKey: "barShadowDirectionSource"
options: [I18n.tr("Inherit Global (Default)", "bar shadow direction source option"), I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"), I18n.tr("Manual", "bar shadow direction source option")]
currentValue: {
switch (shadowCard.directionSource) {
case "autoBar":
return I18n.tr("Auto (Bar-aware)", "bar shadow direction source option");
case "manual":
return I18n.tr("Manual", "bar shadow direction source option");
default:
return I18n.tr("Inherit Global (Default)", "bar shadow direction source option");
}
}
onValueChanged: value => {
if (value === I18n.tr("Auto (Bar-aware)", "bar shadow direction source option")) {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirectionMode: "autoBar"
});
} else if (value === I18n.tr("Manual", "bar shadow direction source option")) {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirectionMode: "manual"
});
} else {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirectionMode: "inherit"
});
}
}
}
SettingsDropdownRow {
visible: shadowCard.shadowActive && shadowCard.directionSource === "manual"
text: I18n.tr("Manual Direction", "bar manual shadow direction")
description: I18n.tr("Use a fixed shadow direction for this bar")
settingKey: "barShadowDirectionManual"
options: [I18n.tr("Top", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")]
currentValue: {
switch (selectedBarConfig?.shadowDirection) {
case "topLeft":
return I18n.tr("Top Left", "shadow direction option");
case "topRight":
return I18n.tr("Top Right", "shadow direction option");
case "bottom":
return I18n.tr("Bottom", "shadow direction option");
default:
return I18n.tr("Top", "shadow direction option");
}
}
onValueChanged: value => {
if (value === I18n.tr("Top Left", "shadow direction option")) {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirection: "topLeft"
});
} else if (value === I18n.tr("Top Right", "shadow direction option")) {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirection: "topRight"
});
} else if (value === I18n.tr("Bottom", "shadow direction option")) {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirection: "bottom"
});
} else {
SettingsData.updateBarConfig(selectedBarId, {
shadowDirection: "top"
});
}
}
}
Column {
visible: shadowCard.shadowActive
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Color")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
horizontalAlignment: Text.AlignLeft
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
}
Item {
width: parent.width
height: shadowColorGroup.implicitHeight
DankButtonGroup {
id: shadowColorGroup
anchors.horizontalCenter: parent.horizontalCenter
buttonPadding: parent.width < 420 ? Theme.spacingXS : Theme.spacingS
minButtonWidth: parent.width < 420 ? 36 : 56
textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium
model: [I18n.tr("Default (Black)"), I18n.tr("Surface", "shadow color option"), I18n.tr("Primary"), I18n.tr("Secondary"), I18n.tr("Custom")]
selectionMode: "single"
currentIndex: {
switch (selectedBarConfig?.shadowColorMode || "default") {
case "surface":
return 1;
case "primary":
return 2;
case "secondary":
return 3;
case "custom":
return 4;
default:
return 0;
}
}
onSelectionChanged: (index, selected) => {
if (!selected)
return;
let mode = "default";
switch (index) {
case 1:
mode = "surface";
break;
case 2:
mode = "primary";
break;
case 3:
mode = "secondary";
break;
case 4:
mode = "custom";
break;
}
SettingsData.updateBarConfig(selectedBarId, {
shadowColorMode: mode
});
}
}
}
Rectangle {
visible: selectedBarConfig?.shadowColorMode === "custom"
width: 32
height: 32
radius: 16
color: selectedBarConfig?.shadowCustomColor ?? "#000000"
border.color: Theme.outline
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
PopoutService.colorPickerModal.selectedColor = selectedBarConfig?.shadowCustomColor ?? "#000000";
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Color");
PopoutService.colorPickerModal.onColorSelectedCallback = function (color) {
SettingsData.updateBarConfig(selectedBarId, {
shadowCustomColor: color.toString()
});
};
PopoutService.colorPickerModal.show();
}
}
}
}
}
SettingsCard {
iconName: "rounded_corner"
title: I18n.tr("Corners & Background")
@@ -1377,6 +1140,134 @@ Item {
}
}
SettingsCard {
id: shadowCard
iconName: "layers"
title: I18n.tr("Shadow", "bar shadow settings card")
settingKey: "barShadow"
collapsible: true
expanded: false
visible: selectedBarConfig?.enabled
readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0
readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "text") === "custom"
SettingsSliderRow {
text: I18n.tr("Intensity", "shadow intensity slider")
minimum: 0
maximum: 100
unit: "%"
value: selectedBarConfig?.shadowIntensity ?? 0
onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, {
shadowIntensity: newValue
})
}
SettingsSliderRow {
visible: shadowCard.shadowActive
text: I18n.tr("Opacity")
minimum: 10
maximum: 100
unit: "%"
value: selectedBarConfig?.shadowOpacity ?? 60
onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, {
shadowOpacity: newValue
})
}
Column {
visible: shadowCard.shadowActive
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Color")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
horizontalAlignment: Text.AlignLeft
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
}
Item {
width: parent.width
height: shadowColorGroup.implicitHeight
DankButtonGroup {
id: shadowColorGroup
anchors.horizontalCenter: parent.horizontalCenter
buttonPadding: parent.width < 420 ? Theme.spacingXS : Theme.spacingS
minButtonWidth: parent.width < 420 ? 36 : 56
textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium
model: [I18n.tr("Text", "shadow color option"), I18n.tr("Surface", "shadow color option"), I18n.tr("Primary"), I18n.tr("Secondary"), I18n.tr("Custom")]
selectionMode: "single"
currentIndex: {
switch (selectedBarConfig?.shadowColorMode || "text") {
case "surface":
return 1;
case "primary":
return 2;
case "secondary":
return 3;
case "custom":
return 4;
default:
return 0;
}
}
onSelectionChanged: (index, selected) => {
if (!selected)
return;
let mode = "text";
switch (index) {
case 1:
mode = "surface";
break;
case 2:
mode = "primary";
break;
case 3:
mode = "secondary";
break;
case 4:
mode = "custom";
break;
}
SettingsData.updateBarConfig(selectedBarId, {
shadowColorMode: mode
});
}
}
}
Rectangle {
visible: selectedBarConfig?.shadowColorMode === "custom"
width: 32
height: 32
radius: 16
color: selectedBarConfig?.shadowCustomColor ?? "#000000"
border.color: Theme.outline
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
PopoutService.colorPickerModal.selectedColor = selectedBarConfig?.shadowCustomColor ?? "#000000";
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Color");
PopoutService.colorPickerModal.onColorSelectedCallback = function (color) {
SettingsData.updateBarConfig(selectedBarId, {
shadowCustomColor: color.toString()
});
};
PopoutService.colorPickerModal.show();
}
}
}
}
}
SettingsToggleCard {
iconName: "border_style"
title: I18n.tr("Border")

View File

@@ -1281,15 +1281,6 @@ Item {
}
}
DankActionButton {
iconName: "qr_code"
buttonSize: 28
visible: modelData.secured && modelData.saved
onClicked: {
PopoutService.showWifiQRCodeModal(modelData.ssid);
}
}
DankActionButton {
iconName: isPinned ? "push_pin" : "push_pin"
buttonSize: 28

View File

@@ -274,7 +274,7 @@ Item {
settingKey: "notificationPopupShadowEnabled"
tags: ["notification", "popup", "shadow", "radius", "rounded"]
text: I18n.tr("Popup Shadow")
description: I18n.tr("Show drop shadow on notification popups. Requires M3 Elevation to be enabled in Theme & Colors.")
description: I18n.tr("Show drop shadow on notification popups")
checked: SettingsData.notificationPopupShadowEnabled
onToggled: checked => SettingsData.set("notificationPopupShadowEnabled", checked)
}

View File

@@ -126,15 +126,6 @@ Item {
return Theme.warning;
}
function openM3ShadowColorPicker() {
PopoutService.colorPickerModal.selectedColor = SettingsData.m3ElevationCustomColor ?? "#000000";
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Shadow Color");
PopoutService.colorPickerModal.onColorSelectedCallback = function (color) {
SettingsData.set("m3ElevationCustomColor", color.toString());
};
PopoutService.colorPickerModal.show();
}
function formatThemeAutoTime(isoString) {
if (!isoString)
return "";
@@ -1601,189 +1592,6 @@ Item {
defaultValue: 12
onSliderValueChanged: newValue => SettingsData.setCornerRadius(newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["elevation", "shadow", "lift", "m3", "material"]
settingKey: "m3ElevationEnabled"
text: I18n.tr("Shadows")
description: I18n.tr("Material inspired shadows and elevation on modals, popouts, and dialogs")
checked: SettingsData.m3ElevationEnabled ?? true
onToggled: checked => SettingsData.set("m3ElevationEnabled", checked)
}
SettingsSliderRow {
tab: "theme"
tags: ["elevation", "shadow", "intensity", "blur", "m3"]
settingKey: "m3ElevationIntensity"
text: I18n.tr("Shadow Intensity")
description: I18n.tr("Controls the base blur radius and offset of shadows")
value: SettingsData.m3ElevationIntensity ?? 12
minimum: 0
maximum: 100
unit: "px"
defaultValue: 12
visible: SettingsData.m3ElevationEnabled ?? true
onSliderValueChanged: newValue => SettingsData.set("m3ElevationIntensity", newValue)
}
SettingsSliderRow {
tab: "theme"
tags: ["elevation", "shadow", "opacity", "transparency", "m3"]
settingKey: "m3ElevationOpacity"
text: I18n.tr("Shadow Opacity")
description: I18n.tr("Controls the transparency of the shadow")
value: SettingsData.m3ElevationOpacity ?? 30
minimum: 0
maximum: 100
unit: "%"
defaultValue: 30
visible: SettingsData.m3ElevationEnabled ?? true
onSliderValueChanged: newValue => SettingsData.set("m3ElevationOpacity", newValue)
}
SettingsDropdownRow {
tab: "theme"
tags: ["elevation", "shadow", "color", "m3"]
settingKey: "m3ElevationColorMode"
text: I18n.tr("Shadow Color")
description: I18n.tr("Base color for shadows (opacity is applied automatically)")
options: [I18n.tr("Default (Black)", "shadow color option"), I18n.tr("Text Color", "shadow color option"), I18n.tr("Primary", "shadow color option"), I18n.tr("Surface Variant", "shadow color option"), I18n.tr("Custom", "shadow color option")]
currentValue: {
switch (SettingsData.m3ElevationColorMode) {
case "text":
return I18n.tr("Text Color", "shadow color option");
case "primary":
return I18n.tr("Primary", "shadow color option");
case "surfaceVariant":
return I18n.tr("Surface Variant", "shadow color option");
case "custom":
return I18n.tr("Custom", "shadow color option");
default:
return I18n.tr("Default (Black)", "shadow color option");
}
}
visible: SettingsData.m3ElevationEnabled ?? true
onValueChanged: value => {
if (value === I18n.tr("Primary", "shadow color option")) {
SettingsData.set("m3ElevationColorMode", "primary");
} else if (value === I18n.tr("Surface Variant", "shadow color option")) {
SettingsData.set("m3ElevationColorMode", "surfaceVariant");
} else if (value === I18n.tr("Custom", "shadow color option")) {
SettingsData.set("m3ElevationColorMode", "custom");
openM3ShadowColorPicker();
} else if (value === I18n.tr("Text Color", "shadow color option")) {
SettingsData.set("m3ElevationColorMode", "text");
} else {
SettingsData.set("m3ElevationColorMode", "default");
}
}
}
SettingsDropdownRow {
tab: "theme"
tags: ["elevation", "shadow", "direction", "light", "advanced", "m3"]
settingKey: "m3ElevationLightDirection"
text: I18n.tr("Light Direction")
description: I18n.tr("Controls shadow cast direction for elevation layers")
options: [I18n.tr("Auto (Bar-aware)", "shadow direction option"), I18n.tr("Top (Default)", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")]
currentValue: {
switch (SettingsData.m3ElevationLightDirection) {
case "autoBar":
return I18n.tr("Auto (Bar-aware)", "shadow direction option");
case "topLeft":
return I18n.tr("Top Left", "shadow direction option");
case "topRight":
return I18n.tr("Top Right", "shadow direction option");
case "bottom":
return I18n.tr("Bottom", "shadow direction option");
default:
return I18n.tr("Top (Default)", "shadow direction option");
}
}
visible: SettingsData.m3ElevationEnabled ?? true
onValueChanged: value => {
if (value === I18n.tr("Auto (Bar-aware)", "shadow direction option")) {
SettingsData.set("m3ElevationLightDirection", "autoBar");
} else if (value === I18n.tr("Top Left", "shadow direction option")) {
SettingsData.set("m3ElevationLightDirection", "topLeft");
} else if (value === I18n.tr("Top Right", "shadow direction option")) {
SettingsData.set("m3ElevationLightDirection", "topRight");
} else if (value === I18n.tr("Bottom", "shadow direction option")) {
SettingsData.set("m3ElevationLightDirection", "bottom");
} else {
SettingsData.set("m3ElevationLightDirection", "top");
}
}
}
Item {
visible: (SettingsData.m3ElevationEnabled ?? true) && SettingsData.m3ElevationColorMode === "custom"
width: parent.width
implicitHeight: 36
height: implicitHeight
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
StyledText {
text: I18n.tr("Custom Shadow Color")
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
verticalAlignment: Text.AlignVCenter
}
Rectangle {
width: 26
height: 26
radius: 13
color: SettingsData.m3ElevationCustomColor ?? "#000000"
border.color: Theme.outline
border.width: 1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: openM3ShadowColorPicker()
}
}
}
}
SettingsToggleRow {
tab: "theme"
tags: ["elevation", "shadow", "modal", "dialog", "m3"]
settingKey: "modalElevationEnabled"
text: I18n.tr("Modal Shadows")
description: I18n.tr("Shadow elevation on modals and dialogs")
checked: SettingsData.modalElevationEnabled ?? true
visible: SettingsData.m3ElevationEnabled ?? true
onToggled: checked => SettingsData.set("modalElevationEnabled", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["elevation", "shadow", "popout", "popup", "osd", "dropdown", "m3"]
settingKey: "popoutElevationEnabled"
text: I18n.tr("Popout Shadows")
description: I18n.tr("Shadow elevation on popouts, OSDs, and dropdowns")
checked: SettingsData.popoutElevationEnabled ?? true
visible: SettingsData.m3ElevationEnabled ?? true
onToggled: checked => SettingsData.set("popoutElevationEnabled", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["elevation", "shadow", "bar", "panel", "navigation", "m3"]
settingKey: "barElevationEnabled"
text: I18n.tr("Bar Shadows")
description: I18n.tr("Shadow elevation on bars and panels")
checked: SettingsData.barElevationEnabled ?? true
visible: SettingsData.m3ElevationEnabled ?? true
onToggled: checked => SettingsData.set("barElevationEnabled", checked)
}
}
SettingsCard {
@@ -2329,40 +2137,12 @@ Item {
}
}
SettingsCard {
tab: "theme"
tags: ["icon", "theme", "system"]
title: I18n.tr("Icon Theme")
settingKey: "iconTheme"
SettingsDropdownRow {
tab: "theme"
tags: ["icon", "theme", "system"]
settingKey: "iconTheme"
text: I18n.tr("Icon Theme")
description: I18n.tr("DankShell & System Icons (requires restart)")
currentValue: SettingsData.iconTheme
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 236
options: cachedIconThemes
onValueChanged: value => {
SettingsData.setIconTheme(value);
if (Quickshell.env("QT_QPA_PLATFORMTHEME") != "gtk3" && Quickshell.env("QT_QPA_PLATFORMTHEME") != "qt6ct" && Quickshell.env("QT_QPA_PLATFORMTHEME_QT6") != "qt6ct") {
ToastService.showError(I18n.tr("Missing Environment Variables", "qt theme env error title"), I18n.tr("You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", "qt theme env error body"));
}
}
}
}
SettingsCard {
tab: "theme"
tags: ["matugen", "templates", "theming"]
title: I18n.tr("Matugen Templates")
settingKey: "matugenTemplates"
iconName: "auto_awesome"
collapsible: true
expanded: false
visible: Theme.matugenAvailable
SettingsToggleRow {
@@ -2667,6 +2447,32 @@ Item {
}
}
SettingsCard {
tab: "theme"
tags: ["icon", "theme", "system"]
title: I18n.tr("Icon Theme")
settingKey: "iconTheme"
SettingsDropdownRow {
tab: "theme"
tags: ["icon", "theme", "system"]
settingKey: "iconTheme"
text: I18n.tr("Icon Theme")
description: I18n.tr("DankShell & System Icons (requires restart)")
currentValue: SettingsData.iconTheme
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 236
options: cachedIconThemes
onValueChanged: value => {
SettingsData.setIconTheme(value);
if (Quickshell.env("QT_QPA_PLATFORMTHEME") != "gtk3" && Quickshell.env("QT_QPA_PLATFORMTHEME") != "qt6ct" && Quickshell.env("QT_QPA_PLATFORMTHEME_QT6") != "qt6ct") {
ToastService.showError(I18n.tr("Missing Environment Variables", "qt theme env error title"), I18n.tr("You need to set either:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct\nas environment variables, and then restart the shell.\n\nqt6ct requires qt6ct-kde to be installed.", "qt theme env error body"));
}
}
}
}
SettingsCard {
tab: "theme"
tags: ["system", "app", "theming", "gtk", "qt"]

View File

@@ -663,15 +663,14 @@ Item {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
layer.enabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: Theme.elevationEnabled
shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1)
shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1)
shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0
blurMax: Theme.elevationBlurMax
shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1)
shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.8
shadowColor: Qt.rgba(0, 0, 0, 0.2)
shadowOpacity: 0.2
}
}

View File

@@ -216,15 +216,6 @@ Rectangle {
onToggled: checked => root.updateConfig("showMemoryGraph", checked)
}
DankToggle {
width: parent.width - Theme.spacingM * 2
x: Theme.spacingM
text: I18n.tr("Show Memory in GB")
visible: root.cfg.showMemory
checked: root.cfg.showInGb ?? false
onToggled: checked => root.updateConfig("showInGb", checked)
}
SettingsDivider {}
DankToggle {

View File

@@ -398,14 +398,10 @@ Item {
widgetObj.runningAppsCurrentWorkspace = SettingsData.runningAppsCurrentWorkspace;
widgetObj.runningAppsCurrentMonitor = false;
}
if (widgetId === "diskUsage") {
if (widgetId === "diskUsage")
widgetObj.mountPath = "/";
widgetObj.diskUsageMode = 0;
}
if (widgetId === "cpuUsage" || widgetId === "memUsage" || widgetId === "cpuTemp" || widgetId === "gpuTemp")
widgetObj.minimumWidth = true;
if (widgetId === "memUsage")
widgetObj.showInGb = false;
var widgets = getWidgetsForSection(targetSection).slice();
widgets.push(widgetObj);
@@ -429,7 +425,7 @@ Item {
"id": widget.id,
"enabled": widget.enabled
};
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge"];
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge"];
for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]];
@@ -540,30 +536,6 @@ Item {
setWidgetsForSection(sectionId, widgets);
}
function handleShowInGbChanged(sectionId, widgetIndex, enabled) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget.showInGb = enabled;
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleDiskUsageModeChanged(sectionId, widgetIndex, mode) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget.diskUsageMode = mode;
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
@@ -629,8 +601,6 @@ Item {
item.pciId = widget.pciId;
if (widget.mountPath !== undefined)
item.mountPath = widget.mountPath;
if (widget.diskUsageMode !== undefined)
item.diskUsageMode = widget.diskUsageMode;
if (widget.showNetworkIcon !== undefined)
item.showNetworkIcon = widget.showNetworkIcon;
if (widget.showBluetoothIcon !== undefined)
@@ -659,8 +629,6 @@ Item {
item.minimumWidth = widget.minimumWidth;
if (widget.showSwap !== undefined)
item.showSwap = widget.showSwap;
if (widget.showInGb !== undefined)
item.showInGb = widget.showInGb;
if (widget.mediaSize !== undefined)
item.mediaSize = widget.mediaSize;
if (widget.clockCompactMode !== undefined)
@@ -957,12 +925,6 @@ Item {
onShowSwapChanged: (sectionId, index, enabled) => {
widgetsTab.handleShowSwapChanged(sectionId, index, enabled);
}
onShowInGbChanged: (sectionId, index, enabled) => {
widgetsTab.handleShowInGbChanged(sectionId, index, enabled);
}
onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => {
widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode);
}
onCompactModeChanged: (widgetId, value) => {
widgetsTab.handleCompactModeChanged(sectionId, widgetId, value);
}
@@ -1021,12 +983,6 @@ Item {
onShowSwapChanged: (sectionId, index, enabled) => {
widgetsTab.handleShowSwapChanged(sectionId, index, enabled);
}
onShowInGbChanged: (sectionId, index, enabled) => {
widgetsTab.handleShowInGbChanged(sectionId, index, enabled);
}
onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => {
widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode);
}
onCompactModeChanged: (widgetId, value) => {
widgetsTab.handleCompactModeChanged(sectionId, widgetId, value);
}
@@ -1085,12 +1041,6 @@ Item {
onShowSwapChanged: (sectionId, index, enabled) => {
widgetsTab.handleShowSwapChanged(sectionId, index, enabled);
}
onShowInGbChanged: (sectionId, index, enabled) => {
widgetsTab.handleShowInGbChanged(sectionId, index, enabled);
}
onDiskUsageModeChanged: (sectionId, widgetIndex, mode) => {
widgetsTab.handleDiskUsageModeChanged(sectionId, widgetIndex, mode);
}
onCompactModeChanged: (widgetId, value) => {
widgetsTab.handleCompactModeChanged(sectionId, widgetId, value);
}

View File

@@ -30,8 +30,6 @@ Column {
signal privacySettingChanged(string sectionId, int widgetIndex, string settingName, bool value)
signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled)
signal showSwapChanged(string sectionId, int widgetIndex, bool enabled)
signal showInGbChanged(string sectionId, int widgetIndex, bool enabled)
signal diskUsageModeChanged(string sectionId, int widgetIndex, int mode)
signal overflowSettingChanged(string sectionId, int widgetIndex, string settingName, var value)
function cloneWidgetData(widget) {
@@ -39,7 +37,7 @@ Column {
"id": widget.id,
"enabled": widget.enabled
};
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge"];
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge"];
for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]];
@@ -69,6 +67,53 @@ Column {
color: Theme.surfaceText
Layout.alignment: Qt.AlignVCenter
}
Item {
height: 1
Layout.fillWidth: true
}
RowLayout {
spacing: Theme.spacingXS
Layout.alignment: Qt.AlignVCenter
visible: root.sectionId === "center"
DankActionButton {
id: indexCenterButton
buttonSize: 28
iconName: "format_list_numbered"
iconSize: 16
iconColor: SettingsData.centeringMode === "index" ? Theme.primary : Theme.outline
onClicked: {
console.log("Centering mode changed to: index");
SettingsData.set("centeringMode", "index");
}
onEntered: {
sharedTooltip.show("Index Centering", indexCenterButton, 0, 0, "bottom");
}
onExited: {
sharedTooltip.hide();
}
}
DankActionButton {
id: geometricCenterButton
buttonSize: 28
iconName: "center_focus_weak"
iconSize: 16
iconColor: SettingsData.centeringMode === "geometric" ? Theme.primary : Theme.outline
onClicked: {
console.log("Centering mode changed to: geometric");
SettingsData.set("centeringMode", "geometric");
}
onEntered: {
sharedTooltip.show("Geometric Centering", geometricCenterButton, 0, 0, "bottom");
}
onExited: {
sharedTooltip.hide();
}
}
}
}
Column {
@@ -90,7 +135,6 @@ Column {
height: 70
z: held ? 2 : 1
Rectangle {
id: itemBackground
@@ -231,34 +275,6 @@ Column {
}
}
DankActionButton {
id: diskMenuButton
visible: modelData.id === "diskUsage"
buttonSize: 32
iconName: "more_vert"
iconSize: 18
iconColor: Theme.outline
onClicked: {
diskUsageContextMenu.widgetData = modelData;
diskUsageContextMenu.sectionId = root.sectionId;
diskUsageContextMenu.widgetIndex = index;
var buttonPos = diskMenuButton.mapToItem(root, 0, 0);
var xPos = buttonPos.x - diskUsageContextMenu.width - Theme.spacingS;
if (xPos < 0)
xPos = buttonPos.x + diskMenuButton.width + Theme.spacingS;
var yPos = buttonPos.y - diskUsageContextMenu.height / 2 + diskMenuButton.height / 2;
if (yPos < 0)
yPos = Theme.spacingS;
else if (yPos + diskUsageContextMenu.height > root.height)
yPos = root.height - diskUsageContextMenu.height - Theme.spacingS;
diskUsageContextMenu.x = xPos;
diskUsageContextMenu.y = yPos;
diskUsageContextMenu.open();
}
}
Item {
width: 32
height: 32
@@ -338,36 +354,23 @@ Column {
}
DankActionButton {
id: memMenuButton
id: showSwapButton
buttonSize: 28
visible: modelData.id === "memUsage"
buttonSize: 32
iconName: "more_vert"
iconSize: 18
iconColor: Theme.outline
iconName: "swap_horiz"
iconSize: 16
iconColor: (modelData.showSwap !== undefined ? modelData.showSwap : false) ? Theme.primary : Theme.outline
onClicked: {
memUsageContextMenu.widgetData = modelData;
memUsageContextMenu.sectionId = root.sectionId;
memUsageContextMenu.widgetIndex = index;
var buttonPos = memMenuButton.mapToItem(root, 0, 0);
var popupWidth = memUsageContextMenu.width;
var popupHeight = memUsageContextMenu.height;
var xPos = buttonPos.x - popupWidth - Theme.spacingS;
if (xPos < 0) {
xPos = buttonPos.x + memMenuButton.width + Theme.spacingS;
}
var yPos = buttonPos.y - popupHeight / 2 + memMenuButton.height / 2;
if (yPos < 0) {
yPos = Theme.spacingS;
} else if (yPos + popupHeight > root.height) {
yPos = root.height - popupHeight - Theme.spacingS;
}
memUsageContextMenu.x = xPos;
memUsageContextMenu.y = yPos;
memUsageContextMenu.open();
var currentEnabled = modelData.showSwap !== undefined ? modelData.showSwap : false;
root.showSwapChanged(root.sectionId, index, !currentEnabled);
}
onEntered: {
var currentEnabled = modelData.showSwap !== undefined ? modelData.showSwap : false;
const tooltipText = currentEnabled ? "Hide Swap" : "Show Swap";
sharedTooltip.show(tooltipText, showSwapButton, 0, 0, "bottom");
}
onExited: {
sharedTooltip.hide();
}
}
@@ -796,257 +799,6 @@ Column {
}
}
Popup {
id: memUsageContextMenu
property var widgetData: null
property string sectionId: ""
property int widgetIndex: -1
width: 200
height: 80
padding: 0
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
background: Rectangle {
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 0
}
contentItem: Item {
Column {
anchors.fill: parent
anchors.margins: Theme.spacingS
spacing: 2
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: swapToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "swap_horiz"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Show Swap")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: swapToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
checked: memUsageContextMenu.widgetData?.showSwap ?? false
onToggled: {
root.showSwapChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, toggled);
}
}
MouseArea {
id: swapToggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
swapToggle.checked = !swapToggle.checked;
root.showSwapChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, swapToggle.checked);
}
}
}
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: gbToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "straighten"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Show in GB")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: gbToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
checked: memUsageContextMenu.widgetData?.showInGb ?? false
onToggled: {
root.showInGbChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, toggled);
}
}
MouseArea {
id: gbToggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
gbToggle.checked = !gbToggle.checked;
root.showInGbChanged(memUsageContextMenu.sectionId, memUsageContextMenu.widgetIndex, gbToggle.checked);
}
}
}
}
}
}
Popup {
id: diskUsageContextMenu
property var widgetData: null
property string sectionId: ""
property int widgetIndex: -1
readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData
width: 240
height: diskMenuColumn.implicitHeight + Theme.spacingS * 2
padding: 0
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
background: Rectangle {
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 0
}
contentItem: Item {
Column {
id: diskMenuColumn
anchors.fill: parent
anchors.margins: Theme.spacingS
spacing: 2
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: "transparent"
StyledText {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
text: I18n.tr("Disk Usage Display")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
}
Repeater {
model: [
{ label: I18n.tr("Percentage"), mode: 0, icon: "percent" },
{ label: I18n.tr("Total"), mode: 1, icon: "storage" },
{ label: I18n.tr("Remaining"), mode: 2, icon: "hourglass_empty" },
{ label: I18n.tr("Remaining / Total"), mode: 3, icon: "pie_chart" }
]
delegate: Rectangle {
required property var modelData
required property int index
width: diskMenuColumn.width
height: 32
radius: Theme.cornerRadius
color: diskOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
function isSelected() {
return (diskUsageContextMenu.currentWidgetData?.diskUsageMode ?? 0) === modelData.mode;
}
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: modelData.icon
size: 16
color: isSelected() ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.label
font.pixelSize: Theme.fontSizeSmall
color: isSelected() ? Theme.primary : Theme.surfaceText
font.weight: isSelected() ? Font.Medium : Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankIcon {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
name: "check"
size: 16
color: Theme.primary
visible: isSelected()
}
MouseArea {
id: diskOptionArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.diskUsageModeChanged(diskUsageContextMenu.sectionId, diskUsageContextMenu.widgetIndex, modelData.mode);
diskUsageContextMenu.close();
}
}
}
}
}
}
}
Popup {
id: controlCenterContextMenu

View File

@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import qs.Common
@@ -95,6 +96,7 @@ PanelWindow {
}
}
radius: Theme.cornerRadius
layer.enabled: true
opacity: shouldBeVisible ? 1 : 0
Column {
@@ -404,15 +406,13 @@ PanelWindow {
onClicked: ToastService.hideToast()
}
ElevationShadow {
anchors.fill: parent
z: -1
level: Theme.elevationLevel3
fallbackOffset: 6
targetRadius: toast.radius
targetColor: toast.color
shadowOpacity: Theme.elevationLevel3 && Theme.elevationLevel3.alpha !== undefined ? Theme.elevationLevel3.alpha : 0.3
shadowEnabled: Theme.elevationEnabled
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.8
shadowColor: Qt.rgba(0, 0, 0, 0.3)
shadowOpacity: 0.3
}
Behavior on opacity {

View File

@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
@@ -16,61 +17,59 @@ Item {
readonly property var allWorkspaces: Hyprland.workspaces?.values || []
readonly property var allWorkspaceIds: {
const workspaces = allWorkspaces;
if (!workspaces || workspaces.length === 0)
return [];
const workspaces = allWorkspaces
if (!workspaces || workspaces.length === 0) return []
try {
const ids = workspaces.map(ws => ws?.id).filter(id => id !== null && id !== undefined);
return ids.sort((a, b) => a - b);
const ids = workspaces.map(ws => ws?.id).filter(id => id !== null && id !== undefined)
return ids.sort((a, b) => a - b)
} catch (e) {
return [];
return []
}
}
readonly property var thisMonitorWorkspaceIds: {
const workspaces = allWorkspaces;
const mon = monitor;
if (!workspaces || workspaces.length === 0 || !mon)
return [];
const workspaces = allWorkspaces
const mon = monitor
if (!workspaces || workspaces.length === 0 || !mon) return []
try {
const filtered = workspaces.filter(ws => ws?.monitor?.name === mon.name);
return filtered.map(ws => ws?.id).filter(id => id !== null && id !== undefined).sort((a, b) => a - b);
const filtered = workspaces.filter(ws => ws?.monitor?.name === mon.name)
return filtered.map(ws => ws?.id).filter(id => id !== null && id !== undefined).sort((a, b) => a - b)
} catch (e) {
return [];
return []
}
}
readonly property var displayedWorkspaceIds: {
if (!allWorkspaceIds || allWorkspaceIds.length === 0) {
const result = [];
const result = []
for (let i = 1; i <= workspacesShown; i++) {
result.push(i);
result.push(i)
}
return result;
return result
}
try {
const maxExisting = Math.max(...allWorkspaceIds);
const totalNeeded = Math.max(workspacesShown, allWorkspaceIds.length);
const result = [];
const maxExisting = Math.max(...allWorkspaceIds)
const totalNeeded = Math.max(workspacesShown, allWorkspaceIds.length)
const result = []
for (let i = 1; i <= maxExisting; i++) {
result.push(i);
result.push(i)
}
let nextId = maxExisting + 1;
let nextId = maxExisting + 1
while (result.length < totalNeeded) {
result.push(nextId);
nextId++;
result.push(nextId)
nextId++
}
return result;
return result
} catch (e) {
const result = [];
const result = []
for (let i = 1; i <= workspacesShown; i++) {
result.push(i);
result.push(i)
}
return result;
return result
}
}
@@ -82,27 +81,24 @@ Item {
readonly property int effectiveRows: Math.max(SettingsData.overviewRows, Math.ceil(displayWorkspaceCount / effectiveColumns))
function getWorkspaceMonitorName(workspaceId) {
if (!allWorkspaces || !workspaceId)
return "";
if (!allWorkspaces || !workspaceId) return ""
try {
const ws = allWorkspaces.find(w => w?.id === workspaceId);
return ws?.monitor?.name ?? "";
const ws = allWorkspaces.find(w => w?.id === workspaceId)
return ws?.monitor?.name ?? ""
} catch (e) {
return "";
return ""
}
}
function workspaceHasWindows(workspaceId) {
if (!workspaceId)
return false;
if (!workspaceId) return false
try {
const workspace = allWorkspaces.find(ws => ws?.id === workspaceId);
if (!workspace)
return false;
const toplevels = workspace?.toplevels?.values || [];
return toplevels.length > 0;
const workspace = allWorkspaces.find(ws => ws?.id === workspaceId)
if (!workspace) return false
const toplevels = workspace?.toplevels?.values || []
return toplevels.length > 0
} catch (e) {
return false;
return false
}
}
@@ -128,16 +124,16 @@ Item {
implicitHeight: overviewBackground.implicitHeight + Theme.spacingL * 2
Component.onCompleted: {
Hyprland.refreshToplevels();
Hyprland.refreshWorkspaces();
Hyprland.refreshMonitors();
Hyprland.refreshToplevels()
Hyprland.refreshWorkspaces()
Hyprland.refreshMonitors()
}
onOverviewOpenChanged: {
if (overviewOpen) {
Hyprland.refreshToplevels();
Hyprland.refreshWorkspaces();
Hyprland.refreshMonitors();
Hyprland.refreshToplevels()
Hyprland.refreshWorkspaces()
Hyprland.refreshMonitors()
}
}
@@ -152,15 +148,15 @@ Item {
radius: Theme.cornerRadius
color: Theme.surfaceContainer
ElevationShadow {
anchors.fill: parent
z: -1
level: Theme.elevationLevel2
fallbackOffset: 4
targetRadius: Theme.cornerRadius
targetColor: Theme.surfaceContainer
shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowBlur: 0.5
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowColor: Theme.shadowStrong
shadowOpacity: 1
blurMax: 32
}
ColumnLayout {
@@ -221,8 +217,8 @@ Item {
acceptedButtons: Qt.LeftButton
onClicked: {
if (root.draggingTargetWorkspace === -1) {
root.overviewOpen = false;
Hyprland.dispatch(`workspace ${workspaceValue}`);
root.overviewOpen = false
Hyprland.dispatch(`workspace ${workspaceValue}`)
}
}
}
@@ -230,15 +226,13 @@ Item {
DropArea {
anchors.fill: parent
onEntered: {
root.draggingTargetWorkspace = workspaceValue;
if (root.draggingFromWorkspace == root.draggingTargetWorkspace)
return;
hoveredWhileDragging = true;
root.draggingTargetWorkspace = workspaceValue
if (root.draggingFromWorkspace == root.draggingTargetWorkspace) return
hoveredWhileDragging = true
}
onExited: {
hoveredWhileDragging = false;
if (root.draggingTargetWorkspace == workspaceValue)
root.draggingTargetWorkspace = -1;
hoveredWhileDragging = false
if (root.draggingTargetWorkspace == workspaceValue) root.draggingTargetWorkspace = -1
}
}
}
@@ -256,28 +250,27 @@ Item {
Repeater {
model: ScriptModel {
values: {
const workspaces = root.allWorkspaces;
const minId = root.minWorkspaceId;
const maxId = root.maxWorkspaceId;
const workspaces = root.allWorkspaces
const minId = root.minWorkspaceId
const maxId = root.maxWorkspaceId
if (!workspaces || workspaces.length === 0)
return [];
if (!workspaces || workspaces.length === 0) return []
try {
const result = [];
const result = []
for (const workspace of workspaces) {
const wsId = workspace?.id ?? -1;
const wsId = workspace?.id ?? -1
if (wsId >= minId && wsId <= maxId) {
const toplevels = workspace?.toplevels?.values || [];
const toplevels = workspace?.toplevels?.values || []
for (const toplevel of toplevels) {
result.push(toplevel);
result.push(toplevel)
}
}
}
return result;
return result
} catch (e) {
console.error("OverviewWidget filter error:", e);
return [];
console.error("OverviewWidget filter error:", e)
return []
}
}
}
@@ -289,19 +282,17 @@ Item {
readonly property int windowWorkspaceId: modelData?.workspace?.id ?? -1
function getWorkspaceIndex() {
if (!root.displayedWorkspaceIds || root.displayedWorkspaceIds.length === 0)
return 0;
if (!windowWorkspaceId || windowWorkspaceId < 0)
return 0;
if (!root.displayedWorkspaceIds || root.displayedWorkspaceIds.length === 0) return 0
if (!windowWorkspaceId || windowWorkspaceId < 0) return 0
try {
for (let i = 0; i < root.displayedWorkspaceIds.length; i++) {
if (root.displayedWorkspaceIds[i] === windowWorkspaceId) {
return i;
return i
}
}
return 0;
return 0
} catch (e) {
return 0;
return 0
}
}
@@ -334,48 +325,48 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
drag.target: parent
onPressed: mouse => {
root.draggingFromWorkspace = windowData?.workspace.id;
window.pressed = true;
window.Drag.active = true;
window.Drag.source = window;
window.Drag.hotSpot.x = mouse.x;
window.Drag.hotSpot.y = mouse.y;
onPressed: (mouse) => {
root.draggingFromWorkspace = windowData?.workspace.id
window.pressed = true
window.Drag.active = true
window.Drag.source = window
window.Drag.hotSpot.x = mouse.x
window.Drag.hotSpot.y = mouse.y
}
onReleased: {
const targetWorkspace = root.draggingTargetWorkspace;
window.pressed = false;
window.Drag.active = false;
root.draggingFromWorkspace = -1;
root.draggingTargetWorkspace = -1;
const targetWorkspace = root.draggingTargetWorkspace
window.pressed = false
window.Drag.active = false
root.draggingFromWorkspace = -1
root.draggingTargetWorkspace = -1
if (targetWorkspace !== -1 && targetWorkspace !== windowData?.workspace.id) {
Hyprland.dispatch(`movetoworkspacesilent ${targetWorkspace},address:${windowData?.address}`);
Hyprland.dispatch(`movetoworkspacesilent ${targetWorkspace},address:${windowData?.address}`)
Qt.callLater(() => {
Hyprland.refreshToplevels();
Hyprland.refreshWorkspaces();
Hyprland.refreshToplevels()
Hyprland.refreshWorkspaces()
Qt.callLater(() => {
window.x = window.initX;
window.y = window.initY;
});
});
window.x = window.initX
window.y = window.initY
})
})
} else {
window.x = window.initX;
window.y = window.initY;
window.x = window.initX
window.y = window.initY
}
}
onClicked: event => {
if (!windowData || !windowData.address)
return;
onClicked: (event) => {
if (!windowData || !windowData.address) return
if (event.button === Qt.LeftButton) {
root.overviewOpen = false;
Hyprland.dispatch(`focuswindow address:${windowData.address}`);
event.accepted = true;
root.overviewOpen = false
Hyprland.dispatch(`focuswindow address:${windowData.address}`)
event.accepted = true
} else if (event.button === Qt.MiddleButton) {
Hyprland.dispatch(`closewindow address:${windowData.address}`);
event.accepted = true;
Hyprland.dispatch(`closewindow address:${windowData.address}`)
event.accepted = true
}
}
}

View File

@@ -11,7 +11,7 @@ Singleton {
id: root
readonly property string currentVersion: "1.4"
readonly property bool changelogEnabled: false
readonly property bool changelogEnabled: true
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion

View File

@@ -1,6 +1,8 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtCore
import QtQuick
import Quickshell
import Quickshell.Io
@@ -11,9 +13,6 @@ Singleton {
property bool dsearchAvailable: false
property int searchIdCounter: 0
property int indexVersion: 0
property bool supportsTypeFilter: false
property bool versionChecked: false
signal searchResultsReceived(var results)
signal statsReceived(var stats)
@@ -27,157 +26,118 @@ Singleton {
stdout: SplitParser {
onRead: line => {
if (line && line.trim().length > 0) {
root.dsearchAvailable = true;
root.dsearchAvailable = true
}
}
}
onExited: exitCode => {
if (exitCode !== 0) {
root.dsearchAvailable = false;
} else {
root._checkVersion();
root.dsearchAvailable = false
}
}
}
function _checkVersion() {
Proc.runCommand("dsearch-version", ["dsearch", "version", "--json"], (stdout, exitCode) => {
root.versionChecked = true;
if (exitCode !== 0)
return;
const response = JSON.parse(stdout);
root.indexVersion = response.index_schema || 0;
root.supportsTypeFilter = root.indexVersion >= 2;
});
}
function ping(callback) {
if (!dsearchAvailable) {
if (callback) {
callback({
"error": "dsearch not available"
});
callback({ "error": "dsearch not available" })
}
return;
return
}
Proc.runCommand("dsearch-ping", ["dsearch", "ping", "--json"], (stdout, exitCode) => {
if (callback) {
if (exitCode === 0) {
try {
const response = JSON.parse(stdout);
callback({
"result": response
});
const response = JSON.parse(stdout)
callback({ "result": response })
} catch (e) {
callback({
"error": "failed to parse ping response"
});
callback({ "error": "failed to parse ping response" })
}
} else {
callback({
"error": "ping failed"
});
callback({ "error": "ping failed" })
}
}
});
})
}
function search(query, params, callback) {
if (!query || query.length === 0) {
if (callback) {
callback({
"error": "query is required"
});
callback({ "error": "query is required" })
}
return;
return
}
if (!dsearchAvailable) {
if (callback) {
callback({
"error": "dsearch not available"
});
callback({ "error": "dsearch not available" })
}
return;
return
}
const args = ["dsearch", "search", query, "--json"];
const args = ["dsearch", "search", query, "--json"]
if (params) {
if (params.limit !== undefined) {
args.push("-n", String(params.limit));
}
if (params.type) {
args.push("-t", params.type);
args.push("-n", String(params.limit))
}
if (params.ext) {
args.push("-e", params.ext);
}
if (params.folder) {
args.push("--folder", params.folder);
args.push("-e", params.ext)
}
if (params.field) {
args.push("-f", params.field);
args.push("-f", params.field)
}
if (params.fuzzy) {
args.push("--fuzzy");
args.push("--fuzzy")
}
if (params.sort) {
args.push("--sort", params.sort);
args.push("--sort", params.sort)
}
if (params.desc !== undefined) {
args.push("--desc=" + (params.desc ? "true" : "false"));
args.push("--desc=" + (params.desc ? "true" : "false"))
}
if (params.minSize !== undefined) {
args.push("--min-size", String(params.minSize));
args.push("--min-size", String(params.minSize))
}
if (params.maxSize !== undefined) {
args.push("--max-size", String(params.maxSize));
args.push("--max-size", String(params.maxSize))
}
}
Proc.runCommand("dsearch-search", args, (stdout, exitCode) => {
if (exitCode === 0) {
try {
const response = JSON.parse(stdout);
searchResultsReceived(response);
const response = JSON.parse(stdout)
searchResultsReceived(response)
if (callback) {
callback({
"result": response
});
callback({ "result": response })
}
} catch (e) {
const error = "failed to parse search response";
errorOccurred(error);
const error = "failed to parse search response"
errorOccurred(error)
if (callback) {
callback({
"error": error
});
callback({ "error": error })
}
}
} else if (exitCode === 124) {
const error = "search timed out";
errorOccurred(error);
const error = "search timed out"
errorOccurred(error)
if (callback) {
callback({
"error": error
});
callback({ "error": error })
}
} else {
const error = "search failed";
errorOccurred(error);
const error = "search failed"
errorOccurred(error)
if (callback) {
callback({
"error": error
});
callback({ "error": error })
}
}
}, 100, 5000);
}, 100, 5000)
}
function rediscover() {
checkProcess.running = true;
checkProcess.running = true
}
}

View File

@@ -41,8 +41,6 @@ Singleton {
property var notificationModal: null
property var wifiPasswordModal: null
property var wifiPasswordModalLoader: null
property var wifiQRCodeModal: null
property var wifiQRCodeModalLoader: null
property var polkitAuthModal: null
property var polkitAuthModalLoader: null
property var bluetoothPairingModal: null
@@ -663,13 +661,6 @@ Singleton {
wifiPasswordModal.show(ssid);
}
function showWifiQRCodeModal(ssid) {
if (wifiQRCodeModalLoader)
wifiQRCodeModalLoader.active = true;
if (wifiQRCodeModal)
wifiQRCodeModal.show(ssid);
}
function showHiddenNetworkModal() {
if (wifiPasswordModalLoader)
wifiPasswordModalLoader.active = true;

View File

@@ -1 +1 @@
v1.5-beta
v1.4.3

View File

@@ -98,7 +98,7 @@ Item {
sourceComponent: IconImage {
anchors.fill: parent
source: root.iconPath
backer.sourceSize: Qt.size(root.iconSize * 2, root.iconSize * 2)
backer.sourceSize: Qt.size(root.iconSize, root.iconSize)
mipmap: true
asynchronous: true
visible: status === Image.Ready

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Window
import QtQuick.Effects
import qs.Common
import qs.Widgets
@@ -19,30 +18,9 @@ Rectangle {
signal imageSaved(string filePath)
property string _pendingSavePath: ""
property var _attachedWindow: root.Window.window
on_AttachedWindowChanged: {
if (_attachedWindow && _pendingSavePath !== "") {
Qt.callLater(function () {
if (root._pendingSavePath !== "") {
let path = root._pendingSavePath;
root._pendingSavePath = "";
root.saveImageToFile(path);
}
});
}
}
function saveImageToFile(filePath) {
if (activeImage.status !== Image.Ready)
return false;
if (!activeImage.Window.window) {
_pendingSavePath = filePath;
return true;
}
activeImage.grabToImage(function (result) {
if (result && result.saveToFile(filePath)) {
root.imageSaved(filePath);
@@ -81,8 +59,6 @@ Rectangle {
mipmap: true
cache: true
visible: false
sourceSize.width: Math.max(width * 2, 128)
sourceSize.height: Math.max(height * 2, 128)
source: !root.shouldProbe ? root.imageSource : ""
}

View File

@@ -1,6 +1,7 @@
import "../Common/fzf.js" as Fzf
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import qs.Common
import qs.Widgets
@@ -253,8 +254,6 @@ Item {
}
contentItem: Rectangle {
id: contentSurface
LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1)
@@ -262,17 +261,12 @@ Item {
border.width: 2
radius: Theme.cornerRadius
ElevationShadow {
id: shadowLayer
anchors.fill: parent
z: -1
level: Theme.elevationLevel2
fallbackOffset: 4
targetRadius: contentSurface.radius
targetColor: contentSurface.color
borderColor: contentSurface.border.color
borderWidth: contentSurface.border.width
shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowBlur: 0.4
shadowColor: Theme.shadowStrong
shadowVerticalOffset: 4
}
Column {

View File

@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import qs.Common
import qs.Widgets
@@ -131,20 +132,16 @@ Rectangle {
}
contentItem: Rectangle {
id: contentSurface
color: Theme.surface
radius: Theme.cornerRadius
ElevationShadow {
id: shadowLayer
anchors.fill: parent
z: -1
level: Theme.elevationLevel2
fallbackOffset: 4
targetRadius: contentSurface.radius
targetColor: contentSurface.color
shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25
shadowEnabled: Theme.elevationEnabled
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowColor: Theme.shadowStrong
shadowBlur: 0.8
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
}
Rectangle {

View File

@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import qs.Common
@@ -256,7 +257,11 @@ PanelWindow {
scale: shouldBeVisible ? 1 : 0.9
property bool childHovered: false
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: shouldBeVisible ? Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha)) : 0
Rectangle {
id: background
@@ -268,20 +273,38 @@ PanelWindow {
z: -1
}
ElevationShadow {
Item {
id: bgShadowLayer
anchors.fill: parent
visible: osdContainer.popupSurfaceAlpha >= 0.95
z: -1
level: Theme.elevationLevel3
fallbackOffset: 6
targetRadius: Theme.cornerRadius
targetColor: Theme.surfaceContainer
borderColor: Theme.outlineMedium
borderWidth: 1
shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, osdContainer.effectiveShadowAlpha);
}
}
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.outlineMedium
border.width: 1
}
}
MouseArea {

View File

@@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import qs.Common
@@ -30,7 +31,6 @@ Item {
property bool backgroundInteractive: true
property bool contentHandlesKeys: false
property bool fullHeightSurface: false
property bool _primeContent: false
property bool _resizeActive: false
property real _surfaceMarginLeft: 0
property real _surfaceW: 0
@@ -77,38 +77,6 @@ Item {
property int effectiveBarPosition: 0
property real effectiveBarBottomGap: 0
readonly property string autoBarShadowDirection: {
const section = triggerSection || "center";
switch (effectiveBarPosition) {
case SettingsData.Position.Top:
if (section === "left")
return "topLeft";
if (section === "right")
return "topRight";
return "top";
case SettingsData.Position.Bottom:
if (section === "left")
return "bottomLeft";
if (section === "right")
return "bottomRight";
return "bottom";
case SettingsData.Position.Left:
if (section === "left")
return "topLeft";
if (section === "right")
return "bottomLeft";
return "left";
case SettingsData.Position.Right:
if (section === "left")
return "topRight";
if (section === "right")
return "bottomRight";
return "right";
default:
return "top";
}
}
readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection
// Snapshot mask geometry to prevent background damage on bar updates
property real _frozenMaskX: 0
@@ -121,14 +89,6 @@ Item {
effectiveBarBottomGap = bottomGap !== undefined ? bottomGap : 0;
}
function primeContent() {
_primeContent = true;
}
function clearPrimedContent() {
_primeContent = false;
}
function setTriggerPosition(x, y, width, section, targetScreen, barPosition, barThickness, barSpacing, barConfig) {
triggerX = x;
triggerY = y;
@@ -192,7 +152,6 @@ Item {
function close() {
shouldBeVisible = false;
_primeContent = false;
PopoutManager.popoutChanged();
closeTimer.restart();
}
@@ -238,11 +197,7 @@ Item {
readonly property real screenHeight: screen ? screen.height : 0
readonly property real dpr: screen ? screen.devicePixelRatio : 1
readonly property var shadowLevel: Theme.elevationLevel3
readonly property real shadowFallbackOffset: 6
readonly property real shadowRenderPadding: (Theme.elevationEnabled && SettingsData.popoutElevationEnabled) ? Theme.elevationRenderPadding(shadowLevel, effectiveShadowDirection, shadowFallbackOffset, 8, 16) : 0
readonly property real shadowMotionPadding: Math.max(0, animationOffset)
readonly property real shadowBuffer: Theme.snap(shadowRenderPadding + shadowMotionPadding, dpr)
readonly property real shadowBuffer: 5
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
@@ -302,30 +257,29 @@ Item {
}
})(), dpr)
readonly property real triggeringBarLeftExclusion: (effectiveBarPosition === SettingsData.Position.Left && barWidth > 0) ? Math.max(0, barX + barWidth) : 0
readonly property real triggeringBarTopExclusion: (effectiveBarPosition === SettingsData.Position.Top && barHeight > 0) ? Math.max(0, barY + barHeight) : 0
readonly property real triggeringBarRightExclusion: (effectiveBarPosition === SettingsData.Position.Right && barWidth > 0) ? Math.max(0, screenWidth - barX) : 0
readonly property real triggeringBarBottomExclusion: (effectiveBarPosition === SettingsData.Position.Bottom && barHeight > 0) ? Math.max(0, screenHeight - barY) : 0
readonly property real maskX: {
const triggeringBarX = (effectiveBarPosition === SettingsData.Position.Left && barWidth > 0) ? barWidth : 0;
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0;
return Math.max(triggeringBarLeftExclusion, adjacentLeftBar);
return Math.max(triggeringBarX, adjacentLeftBar);
}
readonly property real maskY: {
const triggeringBarY = (effectiveBarPosition === SettingsData.Position.Top && barHeight > 0) ? barHeight : 0;
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0;
return Math.max(triggeringBarTopExclusion, adjacentTopBar);
return Math.max(triggeringBarY, adjacentTopBar);
}
readonly property real maskWidth: {
const triggeringBarRight = (effectiveBarPosition === SettingsData.Position.Right && barWidth > 0) ? barWidth : 0;
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0;
const rightExclusion = Math.max(triggeringBarRightExclusion, adjacentRightBar);
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar);
return Math.max(100, screenWidth - maskX - rightExclusion);
}
readonly property real maskHeight: {
const triggeringBarBottom = (effectiveBarPosition === SettingsData.Position.Bottom && barHeight > 0) ? barHeight : 0;
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0;
const bottomExclusion = Math.max(triggeringBarBottomExclusion, adjacentBottomBar);
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar);
return Math.max(100, screenHeight - maskY - bottomExclusion);
}
@@ -335,7 +289,7 @@ Item {
visible: false
color: "transparent"
Component.onCompleted: {
if (typeof updatesEnabled !== "undefined" && !root.overlayContent)
if (typeof updatesEnabled !== "undefined")
updatesEnabled = false;
}
@@ -441,7 +395,7 @@ Item {
implicitWidth: useBackgroundWindow ? root._surfaceW : 0
implicitHeight: (useBackgroundWindow && !_fullHeight) ? (root.alignedHeight + shadowBuffer * 2) : 0
mask: useBackgroundWindow ? contentInputMask : null
mask: (useBackgroundWindow && _fullHeight) ? contentInputMask : null
Region {
id: contentInputMask
@@ -451,10 +405,10 @@ Item {
Item {
id: contentMaskRect
visible: false
x: contentContainer.x
y: contentContainer.y
width: root.alignedWidth
height: root.alignedHeight
x: contentContainer.x - root.shadowBuffer
y: contentContainer.y - root.shadowBuffer
width: root.alignedWidth + root.shadowBuffer * 2
height: root.alignedHeight + root.shadowBuffer * 2
}
MouseArea {
@@ -526,20 +480,42 @@ Item {
}
}
ElevationShadow {
Rectangle {
id: shadowSource
anchors.centerIn: parent
width: parent.width
height: parent.height
radius: Theme.cornerRadius
color: "black"
visible: false
opacity: contentWrapper.opacity
scale: contentWrapper.scale
x: contentWrapper.x
y: contentWrapper.y
level: root.shadowLevel
direction: root.effectiveShadowDirection
fallbackOffset: root.shadowFallbackOffset
targetRadius: Theme.cornerRadius
targetColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive)
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
readonly property int blurMax: 64
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive)
layer.smooth: false
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
shadowBlur: Math.max(0, Math.min(1, shadowSource.shadowBlurPx / shadowSource.blurMax))
shadowScale: 1 + (2 * shadowSource.shadowSpreadPx) / Math.max(1, Math.min(shadowSource.width, shadowSource.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
return Theme.withAlpha(baseColor, shadowSource.effectiveShadowAlpha);
}
}
}
Item {
@@ -570,13 +546,13 @@ Item {
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
border.color: Theme.outlineMedium
border.width: 0
border.width: 1
}
Loader {
id: contentLoader
anchors.fill: parent
active: root._primeContent || shouldBeVisible || contentWindow.visible
active: shouldBeVisible || contentWindow.visible
asynchronous: false
}
}

View File

@@ -53,11 +53,8 @@
--m3-radius: 12px;
--m3-radius-sm: 10px;
--m3-elev-0: none;
--m3-elev-1: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 8%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 6%, transparent);
--m3-elev-2: 0 2px 6px color-mix(in srgb, var(--md-sys-color-shadow) 10%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 6%, transparent);
--m3-elev-3: 0 11px 7px color-mix(in srgb, var(--md-sys-color-shadow) 19%, transparent), 0 13px 25px color-mix(in srgb, var(--md-sys-color-shadow) 30%, transparent);
--m3-elev-4: 0 14px 12px color-mix(in srgb, var(--md-sys-color-shadow) 17%, transparent), 0 20px 40px color-mix(in srgb, var(--md-sys-color-shadow) 30%, transparent);
--m3-elev-5: 0 17px 17px color-mix(in srgb, var(--md-sys-color-shadow) 15%, transparent), 0 27px 55px color-mix(in srgb, var(--md-sys-color-shadow) 30%, transparent);
--m3-elev-1: 0 1px 2px rgba(0,0,0,.08), 0 1px 3px rgba(0,0,0,.06);
--m3-elev-2: 0 2px 6px rgba(0,0,0,.10), 0 1px 3px rgba(0,0,0,.06);
--tab-height: 34px;
--urlbar-height: 38px;
@@ -121,11 +118,8 @@
--md-sys-color-surface-container-high: {{colors.surface_container_high.dark.hex}};
--md-sys-color-surface-container-highest: {{colors.surface_container_highest.dark.hex}};
--m3-elev-1: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 50%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 35%, transparent);
--m3-elev-2: 0 4px 10px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent), 0 1px 3px color-mix(in srgb, var(--md-sys-color-shadow) 35%, transparent);
--m3-elev-3: 0 11px 7px color-mix(in srgb, var(--md-sys-color-shadow) 45%, transparent), 0 13px 25px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent);
--m3-elev-4: 0 14px 12px color-mix(in srgb, var(--md-sys-color-shadow) 42%, transparent), 0 20px 40px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent);
--m3-elev-5: 0 17px 17px color-mix(in srgb, var(--md-sys-color-shadow) 40%, transparent), 0 27px 55px color-mix(in srgb, var(--md-sys-color-shadow) 55%, transparent);
--m3-elev-1: 0 1px 2px rgba(0,0,0,.50), 0 1px 3px rgba(0,0,0,.35);
--m3-elev-2: 0 4px 10px rgba(0,0,0,.55), 0 1px 3px rgba(0,0,0,.35);
--state-hover: color-mix(in srgb, var(--md-sys-color-on-surface) 6%, transparent);
--state-press: color-mix(in srgb, var(--md-sys-color-on-surface) 10%, transparent);

View File

@@ -4,12 +4,10 @@ return {
priority = 1000,
config = function()
require('base16-colorscheme').setup({
base00 = '{{colors.background.dark.hex}}',
base01 = '{{colors.surface_container_low.dark.hex}}',
base02 = '{{colors.surface_container.dark.hex}}',
base03 = '{{dank16.color8.dark.hex}}',
base0B = '{{dank16.color3.dark.hex}}',
base00 = '{{dank16.color0.default.hex}}',
base01 = '{{dank16.color0.default.hex}}',
base02 = '{{dank16.color8.default.hex}}',
base03 = '{{dank16.color8.default.hex}}',
base04 = '{{dank16.color7.default.hex}}',
base05 = '{{dank16.color15.default.hex}}',
base06 = '{{dank16.color15.default.hex}}',
@@ -17,12 +15,65 @@ return {
base08 = '{{dank16.color9.default.hex}}',
base09 = '{{dank16.color9.default.hex}}',
base0A = '{{dank16.color12.default.hex}}',
base0B = '{{dank16.color10.default.hex}}',
base0C = '{{dank16.color14.default.hex}}',
base0D = '{{dank16.color12.default.hex}}',
base0E = '{{dank16.color13.default.hex}}',
base0F = '{{dank16.color13.default.hex}}',
})
vim.api.nvim_set_hl(0, 'Visual', {
bg = '{{dank16.color8.default.hex}}',
fg = '{{dank16.color15.default.hex}}',
bold = true
})
vim.api.nvim_set_hl(0, 'Statusline', {
bg = '{{dank16.color12.default.hex}}',
fg = '{{dank16.color0.default.hex}}',
})
vim.api.nvim_set_hl(0, 'LineNr', { fg = '{{dank16.color8.default.hex}}' })
vim.api.nvim_set_hl(0, 'CursorLineNr', { fg = '{{dank16.color14.default.hex}}', bold = true })
vim.api.nvim_set_hl(0, 'Statement', {
fg = '{{dank16.color13.default.hex}}',
bold = true
})
vim.api.nvim_set_hl(0, 'Keyword', { link = 'Statement' })
vim.api.nvim_set_hl(0, 'Repeat', { link = 'Statement' })
vim.api.nvim_set_hl(0, 'Conditional', { link = 'Statement' })
vim.api.nvim_set_hl(0, 'Function', {
fg = '{{dank16.color12.default.hex}}',
bold = true
})
vim.api.nvim_set_hl(0, 'Macro', {
fg = '{{dank16.color12.default.hex}}',
italic = true
})
vim.api.nvim_set_hl(0, '@function.macro', { link = 'Macro' })
vim.api.nvim_set_hl(0, 'Type', {
fg = '{{dank16.color14.default.hex}}',
bold = true,
italic = true
})
vim.api.nvim_set_hl(0, 'Structure', { link = 'Type' })
vim.api.nvim_set_hl(0, 'String', {
fg = '{{dank16.color10.default.hex}}',
italic = true
})
vim.api.nvim_set_hl(0, 'Operator', { fg = '{{dank16.color7.default.hex}}' })
vim.api.nvim_set_hl(0, 'Delimiter', { fg = '{{dank16.color7.default.hex}}' })
vim.api.nvim_set_hl(0, '@punctuation.bracket', { link = 'Delimiter' })
vim.api.nvim_set_hl(0, '@punctuation.delimiter', { link = 'Delimiter' })
vim.api.nvim_set_hl(0, 'Comment', {
fg = '{{dank16.color8.default.hex}}',
italic = true
})
local current_file_path = vim.fn.stdpath("config") .. "/lua/plugins/dankcolors.lua"
if not _G._matugen_theme_watcher then
local uv = vim.uv or vim.loop

View File

@@ -2400,74 +2400,6 @@
],
"description": "0 = square corners"
},
{
"section": "m3ElevationEnabled",
"label": "M3 Elevation & Shadows",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"appearance",
"elevation",
"lift",
"material",
"m3",
"shadow",
"shadows",
"theme"
],
"description": "Material Design 3 shadows and elevation on modals, popouts, and dialogs"
},
{
"section": "modalElevationEnabled",
"label": "Modal Shadows",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"dialog",
"elevation",
"m3",
"material",
"modal",
"shadow",
"shadows"
],
"description": "Shadow elevation on modals and dialogs"
},
{
"section": "popoutElevationEnabled",
"label": "Popout Shadows",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"dropdown",
"elevation",
"m3",
"material",
"osd",
"popout",
"popup",
"shadow",
"shadows"
],
"description": "Shadow elevation on popouts, OSDs, and dropdowns"
},
{
"section": "barElevationEnabled",
"label": "Bar Shadows",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"bar",
"elevation",
"m3",
"material",
"navigation",
"panel",
"shadow",
"shadows"
],
"description": "Shadow elevation on bars and panels"
},
{
"section": "cursorSize",
"label": "Cursor Size",