Author SHA1 Message Date
Inorishio 58c187dadf Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 7s
C++ / build (pull_request) Failing after 12s
C++ / clang-tidy (pull_request) Failing after 11s
JS/TS / fmt (pull_request) Successful in 13s
JS/TS / lint (pull_request) Successful in 9s
Python / static (pull_request) Successful in 35s
Rust / build (pull_request) Successful in 1m0s
Python / verify (pull_request) Successful in 1m44s
Rust / fmt (pull_request) Successful in 45s
Rust / clippy (pull_request) Successful in 1m7s
2026-10-22 23:21:20 +02:00
Inorishio 6391bc85c4 Moved network related files, added network sub pages
C++ / fmt (pull_request) Successful in 5s
C++ / build (pull_request) Successful in 2m10s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 17s
Python / static (pull_request) Successful in 44s
C++ / clang-tidy (pull_request) Successful in 3m37s
Rust / build (pull_request) Successful in 1m3s
Rust / fmt (pull_request) Failing after 15m10s
Python / verify (pull_request) Failing after 16m16s
Rust / clippy (pull_request) Successful in 45s
2026-10-18 16:29:12 +02:00
Inorishio d1a045787e merge from main, settings window wifi updates, component creation, remove known network window
C++ / fmt (pull_request) Successful in 6s
C++ / build (pull_request) Successful in 2m9s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 16s
Python / static (pull_request) Successful in 49s
C++ / clang-tidy (pull_request) Successful in 3m34s
Rust / build (pull_request) Successful in 1m1s
Rust / fmt (pull_request) Successful in 31s
Python / verify (pull_request) Successful in 1m45s
Rust / clippy (pull_request) Successful in 45s
2026-09-20 18:44:20 +02:00
Inorishio 7c55d9627a t 2026-09-19 17:24:27 +02:00
Inorishio 5fd2720f00 moved files, set guards to remove unnecessary warnings, created components, started with known network manage list
C++ / fmt (pull_request) Successful in 4s
C++ / build (pull_request) Successful in 2m7s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 16s
C++ / clang-tidy (pull_request) Successful in 3m34s
Python / static (pull_request) Successful in 1m0s
Rust / build (pull_request) Successful in 1m5s
Rust / fmt (pull_request) Successful in 34s
Python / verify (pull_request) Successful in 1m58s
Rust / clippy (pull_request) Successful in 46s
2026-09-19 17:23:43 +02:00
zach 74261f0a49 Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 9s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 14s
Python / static (pull_request) Successful in 1m5s
Rust / fmt (pull_request) Successful in 32s
Rust / build (pull_request) Successful in 1m57s
C++ / build (pull_request) Successful in 3m57s
Rust / clippy (pull_request) Successful in 1m32s
Python / verify (pull_request) Successful in 3m6s
C++ / clang-tidy (pull_request) Successful in 5m23s
2026-08-18 21:47:03 +02:00
zach e76350fa7f Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 3s
JS/TS / lint (pull_request) Successful in 16s
JS/TS / fmt (pull_request) Successful in 17s
Python / static (pull_request) Successful in 56s
Rust / fmt (pull_request) Successful in 58s
Rust / build (pull_request) Successful in 1m51s
C++ / build (pull_request) Successful in 2m32s
Rust / clippy (pull_request) Successful in 1m32s
Python / verify (pull_request) Successful in 2m39s
C++ / clang-tidy (pull_request) Successful in 4m2s
2026-08-18 19:31:42 +02:00
zach 015c1fb27d Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 17s
JS/TS / lint (pull_request) Successful in 20s
Python / static (pull_request) Successful in 57s
Rust / fmt (pull_request) Successful in 1m9s
C++ / build (pull_request) Successful in 2m30s
Rust / build (pull_request) Successful in 2m8s
Rust / clippy (pull_request) Successful in 1m33s
Python / verify (pull_request) Successful in 3m0s
C++ / clang-tidy (pull_request) Successful in 4m7s
2026-08-18 00:04:59 +02:00
zach f6cb7e44c2 Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 8s
JS/TS / fmt (pull_request) Successful in 11s
JS/TS / lint (pull_request) Successful in 15s
Python / static (pull_request) Successful in 54s
Rust / fmt (pull_request) Successful in 30s
Rust / build (pull_request) Successful in 2m2s
C++ / build (pull_request) Successful in 4m0s
Rust / clippy (pull_request) Successful in 1m29s
Python / verify (pull_request) Successful in 3m13s
C++ / clang-tidy (pull_request) Successful in 5m7s
2026-08-17 22:05:33 +02:00
Inorishio 5a8939bc1e changed the repetaer for the networkpopout to be a listview, changed some variables in the bluetooth popout
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 21s
JS/TS / lint (pull_request) Successful in 19s
Python / static (pull_request) Successful in 1m1s
Rust / fmt (pull_request) Successful in 52s
C++ / build (pull_request) Successful in 2m46s
Rust / build (pull_request) Successful in 2m25s
Rust / clippy (pull_request) Successful in 1m58s
Python / verify (pull_request) Successful in 3m16s
C++ / clang-tidy (pull_request) Successful in 6m59s
2026-08-17 22:04:49 +02:00
Inorishio 6071223009 Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 19s
Python / static (pull_request) Successful in 57s
Rust / fmt (pull_request) Successful in 1m9s
Rust / build (pull_request) Successful in 2m11s
C++ / build (pull_request) Successful in 2m34s
Rust / clippy (pull_request) Successful in 1m30s
Python / verify (pull_request) Successful in 2m55s
C++ / clang-tidy (pull_request) Successful in 3m59s
2026-08-16 22:57:54 +02:00
Inorishio 2d40ce33d1 Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 17s
JS/TS / lint (pull_request) Successful in 16s
Python / fmt (pull_request) Successful in 31s
Python / lint (pull_request) Successful in 41s
Python / test (pull_request) Successful in 1m5s
Python / typecheck (pull_request) Successful in 1m15s
Rust / clippy (pull_request) Failing after 12m43s
Rust / fmt (pull_request) Failing after 12m57s
Rust / build (pull_request) Failing after 13m33s
Python / buildcheck (pull_request) Failing after 13m45s
C++ / clang-tidy (pull_request) Failing after 14m23s
C++ / build (pull_request) Failing after 14m25s
2026-08-15 20:38:54 +02:00
zach 954dc10fbb bluetooth model delegate animations
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 19s
JS/TS / lint (pull_request) Successful in 21s
Python / fmt (pull_request) Successful in 35s
Python / lint (pull_request) Successful in 36s
Python / test (pull_request) Successful in 1m3s
Python / typecheck (pull_request) Failing after 1m4s
C++ / build (pull_request) Successful in 1m52s
Rust / build (pull_request) Successful in 1m41s
Rust / fmt (pull_request) Successful in 1m6s
Python / buildcheck (pull_request) Successful in 2m28s
Rust / clippy (pull_request) Successful in 1m55s
C++ / clang-tidy (pull_request) Successful in 3m36s
2026-07-11 14:00:08 +02:00
zach 15ccfd24c6 Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 16s
Python / fmt (pull_request) Successful in 32s
Python / lint (pull_request) Successful in 32s
Python / test (pull_request) Successful in 1m3s
Python / typecheck (pull_request) Failing after 1m3s
C++ / build (pull_request) Successful in 1m41s
Rust / build (pull_request) Successful in 1m42s
Rust / fmt (pull_request) Successful in 1m17s
Python / buildcheck (pull_request) Successful in 2m43s
Rust / clippy (pull_request) Successful in 2m7s
C++ / clang-tidy (pull_request) Successful in 3m43s
2026-07-10 18:20:25 +02:00
zach 33b08523e9 add preliminary bluetooth widget + popout
C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 15s
JS/TS / lint (pull_request) Successful in 17s
Python / fmt (pull_request) Successful in 35s
Python / lint (pull_request) Successful in 34s
Python / test (pull_request) Successful in 1m0s
C++ / build (pull_request) Successful in 1m46s
Rust / fmt (pull_request) Successful in 1m19s
Rust / build (pull_request) Successful in 1m54s
Python / buildcheck (pull_request) Successful in 2m42s
Rust / clippy (pull_request) Successful in 1m54s
C++ / clang-tidy (pull_request) Successful in 3m42s
2026-07-10 16:17:47 +02:00
zach 742bece30b Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 7s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 20s
Python / fmt (pull_request) Successful in 28s
Python / lint (pull_request) Successful in 29s
Python / test (pull_request) Successful in 59s
Rust / fmt (pull_request) Successful in 57s
C++ / build (pull_request) Successful in 3m47s
Rust / build (pull_request) Successful in 2m10s
Python / buildcheck (pull_request) Successful in 2m51s
Rust / clippy (pull_request) Successful in 1m32s
C++ / clang-tidy (pull_request) Successful in 5m9s
2026-07-10 15:23:23 +02:00
zach a64eadd14a feat: add password overlay for network popout + redesign
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 11s
JS/TS / lint (pull_request) Successful in 24s
Python / fmt (pull_request) Successful in 30s
Python / lint (pull_request) Successful in 34s
Python / test (pull_request) Successful in 53s
C++ / build (pull_request) Successful in 1m52s
Rust / fmt (pull_request) Successful in 1m14s
Rust / build (pull_request) Successful in 1m57s
Rust / clippy (pull_request) Successful in 2m0s
Python / buildcheck (pull_request) Successful in 2m37s
C++ / clang-tidy (pull_request) Successful in 3m43s
2026-07-09 17:33:13 +02:00
zach f9eeb793db Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 18s
JS/TS / lint (pull_request) Successful in 19s
Python / fmt (pull_request) Successful in 32s
Python / lint (pull_request) Successful in 36s
Python / test (pull_request) Successful in 55s
C++ / build (pull_request) Successful in 1m55s
Rust / fmt (pull_request) Successful in 1m15s
Rust / build (pull_request) Successful in 1m59s
Python / buildcheck (pull_request) Successful in 2m45s
Rust / clippy (pull_request) Successful in 1m55s
C++ / clang-tidy (pull_request) Successful in 3m41s
2026-07-09 14:22:34 +02:00
zach 6bb193c78c Merge branch 'main' into module/wifi
C++ / fmt (pull_request) Successful in 5s
JS/TS / fmt (pull_request) Successful in 19s
JS/TS / lint (pull_request) Successful in 22s
Python / lint (pull_request) Successful in 33s
Python / fmt (pull_request) Successful in 36s
Python / test (pull_request) Successful in 1m5s
C++ / build (pull_request) Successful in 1m42s
Rust / fmt (pull_request) Successful in 1m11s
Rust / build (pull_request) Successful in 1m56s
Python / buildcheck (pull_request) Successful in 2m40s
Rust / clippy (pull_request) Successful in 1m48s
C++ / clang-tidy (pull_request) Successful in 3m42s
2026-07-08 22:56:46 +02:00
Inorishio aadecbfe44 Chore: created Spacer component, moved x available networks, added connected networks
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 17s
Python / test (pull_request) Successful in 59s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m31s
C++ / build (pull_request) Successful in 2m37s
2026-07-08 22:22:03 +02:00
zach 53f0aa80ae Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 30s
Python / test (pull_request) Successful in 42s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m36s
C++ / build (pull_request) Successful in 2m20s
2026-07-08 13:41:27 +02:00
Inorishio d9856c9409 Chore: created NetworkItem component, renamed network header to Wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 14s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m51s
C++ / build (pull_request) Successful in 2m36s
2026-07-02 22:46:09 +02:00
zach 8dc9753e2b feat: don't add the same network twice
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 30s
Python / lint-format (pull_request) Successful in 48s
Python / test (pull_request) Successful in 40s
C++ / build (pull_request) Successful in 2m8s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m13s
2026-07-02 22:09:25 +02:00
zach 2a4bd3dfdd chore: remove old code
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 17s
Python / lint-format (pull_request) Successful in 31s
Python / test (pull_request) Successful in 39s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m31s
C++ / build (pull_request) Successful in 2m17s
2026-07-02 21:58:01 +02:00
zach f75f51ef50 fix: sort is now correct
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 18s
Python / lint-format (pull_request) Successful in 21s
Python / test (pull_request) Successful in 48s
C++ / build (pull_request) Successful in 2m59s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m12s
2026-07-02 21:54:58 +02:00
zach e0873304d1 add sorting by strength
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 15s
Python / lint-format (pull_request) Successful in 32s
Python / test (pull_request) Successful in 39s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m45s
C++ / build (pull_request) Successful in 2m47s
2026-07-02 21:53:42 +02:00
zach 99a0155c17 Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 14s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m30s
C++ / build (pull_request) Successful in 2m32s
2026-07-02 21:46:15 +02:00
zach f309debea5 set scannerEnabled when popout is visible + remove scan button
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 18s
Python / lint-format (pull_request) Successful in 20s
Python / test (pull_request) Successful in 47s
C++ / build (pull_request) Successful in 3m9s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m15s
2026-07-02 16:06:52 +02:00
zach 0979fd014d Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 16s
Python / lint-format (pull_request) Successful in 32s
Python / test (pull_request) Successful in 38s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m49s
C++ / build (pull_request) Successful in 3m5s
2026-07-02 15:16:22 +02:00
zach 656bd0a54d Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m37s
C++ / build (pull_request) Successful in 2m22s
2026-06-30 22:42:51 +02:00
zach f01001dcfa merge main into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 9s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 49s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m42s
C++ / build (pull_request) Successful in 2m28s
2026-06-30 18:15:43 +02:00
zach bc6b0d50ab Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 34s
Python / lint-format (pull_request) Successful in 35s
Python / test (pull_request) Successful in 1m11s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m58s
C++ / build (pull_request) Successful in 4m31s
2026-06-29 22:10:45 +02:00
zach f27c9afc25 more methods for wifi and scanning + layout
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 15s
Python / test (pull_request) Successful in 29s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s
2026-06-26 15:15:03 +02:00
Inorishio 5962fc8354 Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 17s
Python / lint-format (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m39s
2026-06-24 18:58:36 +02:00
Inorishio 1adcb9841c Added network properties, nicNames, netDevices, networkName < reminder I should use layouts.
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 16s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m52s
2026-06-22 23:34:58 +02:00
Inorishio 0e0f8555ed fixing singleton in helpers for network + getting output from systray 2026-06-15 20:48:01 +02:00
Inorishio 1d63e67554 removed network module and moved it to tray, have a popout window without content! everything still in wi.i.p. 2026-06-13 18:22:03 +02:00
322 changed files with 7839 additions and 14307 deletions
-3
View File
@@ -1,3 +0,0 @@
#omz revision: d2b7f557cceaddb16ba89bbf8200d8a8df35c4d8
#omz fpath: /home/zach/.oh-my-zsh/plugins/colored-man-pages /home/zach/.oh-my-zsh/plugins/universalarchive /home/zach/.oh-my-zsh/plugins/tldr /home/zach/.oh-my-zsh/plugins/extract /home/zach/.oh-my-zsh/plugins/copypath /home/zach/.oh-my-zsh/plugins/cp /home/zach/.oh-my-zsh/plugins/conda-env /home/zach/.oh-my-zsh/plugins/command-not-found /home/zach/.oh-my-zsh/plugins/dirhistory /home/zach/.oh-my-zsh/plugins/copybuffer /home/zach/.oh-my-zsh/plugins/copyfile /home/zach/.oh-my-zsh/custom/plugins/fast-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-autosuggestions /home/zach/.oh-my-zsh/plugins/archlinux /home/zach/.oh-my-zsh/plugins/web-search /home/zach/.oh-my-zsh/plugins/sudo /home/zach/.oh-my-zsh/plugins/git /home/zach/.oh-my-zsh/functions /home/zach/.oh-my-zsh/completions /home/zach/.oh-my-zsh/custom/functions /home/zach/.oh-my-zsh/custom/completions /home/zach/tools/ripgrep/complete /home/linuxbrew/.linuxbrew/share/zsh/site-functions /home/zach/.oh-my-zsh/plugins/colored-man-pages /home/zach/.oh-my-zsh/plugins/universalarchive /home/zach/.oh-my-zsh/plugins/tldr /home/zach/.oh-my-zsh/plugins/extract /home/zach/.oh-my-zsh/plugins/copypath /home/zach/.oh-my-zsh/plugins/cp /home/zach/.oh-my-zsh/plugins/conda-env /home/zach/.oh-my-zsh/plugins/command-not-found /home/zach/.oh-my-zsh/plugins/dirhistory /home/zach/.oh-my-zsh/plugins/copybuffer /home/zach/.oh-my-zsh/plugins/copyfile /home/zach/.oh-my-zsh/custom/plugins/fast-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting /home/zach/.oh-my-zsh/custom/plugins/zsh-autosuggestions /home/zach/.oh-my-zsh/plugins/archlinux /home/zach/.oh-my-zsh/plugins/web-search /home/zach/.oh-my-zsh/plugins/sudo /home/zach/.oh-my-zsh/plugins/git /home/zach/.oh-my-zsh/functions /home/zach/.oh-my-zsh/completions /home/zach/.oh-my-zsh/custom/functions /home/zach/.oh-my-zsh/custom/completions /home/zach/.oh-my-zsh/cache/completions /home/zach/tools/ripgrep/complete /home/linuxbrew/.linuxbrew/share/zsh/site-functions /usr/local/share/zsh/site-functions /usr/share/zsh/site-functions /usr/share/zsh/functions/Calendar /usr/share/zsh/functions/Chpwd /usr/share/zsh/functions/Completion /usr/share/zsh/functions/Completion/Base /usr/share/zsh/functions/Completion/Linux /usr/share/zsh/functions/Completion/Unix /usr/share/zsh/functions/Completion/X /usr/share/zsh/functions/Completion/Zsh /usr/share/zsh/functions/Exceptions /usr/share/zsh/functions/MIME /usr/share/zsh/functions/Math /usr/share/zsh/functions/Misc /usr/share/zsh/functions/Newuser /usr/share/zsh/functions/Prompts /usr/share/zsh/functions/TCP /usr/share/zsh/functions/VCS_Info /usr/share/zsh/functions/VCS_Info/Backends /usr/share/zsh/functions/Zftp /usr/share/zsh/functions/Zle /home/zach/.zfunc
-1
View File
@@ -50,7 +50,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(QT_NO_PRIVATE_MODULE_WARNING ON)
set(ENABLE_MODULES "plugin;shell;cli;m3shapes" CACHE STRING "Modules to build/install")
set(INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/ZShell" CACHE STRING "Library install dir")
+1 -1
View File
@@ -16,7 +16,7 @@ CustomRect {
property color activeOnColor
property bool checked
property real checkedRadius: Tokens.rounding.medium
property real defaultRadius: Tokens.rounding.large
property real defaultRadius: Math.min(width, height) / 2
property color disabledColor: Qt.alpha(Colors.palette.m3onSurface, 0.1)
property color disabledOnColor: Qt.alpha(Colors.palette.m3onSurface, 0.38)
property bool fillWidth
+2
View File
@@ -34,6 +34,7 @@ BusyIndicator {
anchors.fill: parent
bgColor: root.bgColor
fgColor: root.fgColor
hasEndIndicator: false
padding: root.padding
rotation: manager.rotation
startAngle: manager.startFraction * 360
@@ -53,6 +54,7 @@ BusyIndicator {
Anim {
duration: manager.completeEndDuration * Tokens.anim.durations.scale
properties: "opacity,internalStrokeWidth"
type: Anim.DefaultEffects
}
}
-42
View File
@@ -1,42 +0,0 @@
import QtQuick
import Quickshell
import ZShell.Components
Item {
id: root
property real radius
property real topLeftRadius: radius
property real topRightRadius: radius
property real bottomRightRadius: radius
property real bottomLeftRadius: radius
property color color: "transparent"
default property alias contentData: contentItem.data
Item {
id: contentItem
anchors.fill: parent
}
ShaderEffectSource {
id: src
hideSource: true
sourceItem: contentItem
}
RoundedMask {
anchors.fill: parent
source: src
topLeftRadius: root.topLeftRadius
topRightRadius: root.topRightRadius
bottomRightRadius: root.bottomRightRadius
bottomLeftRadius: root.bottomLeftRadius
color: root.color
}
Behavior on color {
CAnim {}
}
}
+4 -3
View File
@@ -99,7 +99,6 @@ ProgressBar {
}
Line {
id: dot
property real implicitSize
anchors.right: parent.right
@@ -125,7 +124,8 @@ ProgressBar {
anchors.left: parent.left
Behavior on implicitWidth {
Anim {}
Anim {
}
}
Component.onCompleted: implicitWidth = Qt.binding(() => parent.width * root.visualPosition)
@@ -222,7 +222,8 @@ ProgressBar {
}
}
Behavior on color {
CAnim {}
CAnim {
}
}
Anim on waveProgress {
duration: root.waveDuration
+6 -6
View File
@@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Templates
import ZShell
import ZShell.Components
import ZShell.Config
import ZShell
import qs.Components
import ZShell.Config
import qs.Services
Slider {
@@ -28,7 +28,7 @@ Slider {
signal interaction(v: real)
implicitHeight: ZUtils.snap(12, root)
implicitHeight: 12
implicitWidth: 200
contentItem: Item {
@@ -123,7 +123,7 @@ Slider {
bottomRightRadius: Tokens.rounding.extraSmall / 2
color: root.fgColor
implicitHeight: root.height
implicitWidth: ZUtils.snap(root.filledWidth, root)
implicitWidth: root.filledWidth
radius: root.radius
topRightRadius: Tokens.rounding.extraSmall / 2
}
@@ -137,8 +137,8 @@ Slider {
frequency: root.waveFrequency
fullLength: root.width - handle.implicitWidth - handle.anchors.leftMargin
implicitHeight: lineWidth * amplitudeMultiplier * 2 + lineWidth
implicitWidth: ZUtils.snap(root.filledWidth, root)
lineWidth: ZUtils.snap(root.height * 0.7, root)
implicitWidth: root.filledWidth
lineWidth: root.height * 0.7
startX: x
Behavior on color {
+1
View File
@@ -150,6 +150,7 @@ TextFieldBase {
sourceComponent: MaterialIcon {
color: Colors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.larger
text: root.leadingIcon
fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build()
}
+39 -41
View File
@@ -2,57 +2,55 @@ import QtQuick
import ZShell.Config
import qs.Services
Item {
CustomClippingRect {
id: track
required property var scrollBar
required property var mouseArea
ClipRect {
radius: Tokens.rounding.full
anchors.left: parent.left
anchors.right: parent.right
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
implicitHeight: handle.implicitHeight
radius: Tokens.rounding.full
CustomRect {
id: handle
anchors.bottom: parent.bottom
implicitHeight: handle.implicitHeight
CustomRect {
id: handle
anchors.bottom: parent.bottom
color: Colors.palette.m3secondary
implicitWidth: track.scrollBar.width * track.scrollBar.effectiveSize
implicitHeight: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
opacity: {
if (!track.scrollBar.enabled)
return 0;
if (track.scrollBar.size === 1)
return 0;
if (track.mouseArea.pressed)
return 1;
if (track.mouseArea.containsMouse)
return 0.8;
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
return 0.6;
color: Colors.palette.m3secondary
implicitWidth: track.scrollBar.width * track.scrollBar.effectiveSize
implicitHeight: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
opacity: {
if (!track.scrollBar.enabled)
return 0;
}
radius: Tokens.rounding.full
x: track.scrollBar.reversed ? track.scrollBar.width * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.width * track.scrollBar.nonAnimY * track.scrollBar.travelScale
if (track.scrollBar.size === 1)
return 0;
if (track.mouseArea.pressed)
return 1;
if (track.mouseArea.containsMouse)
return 0.8;
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
return 0.6;
return 0;
}
radius: Tokens.rounding.full
x: track.scrollBar.reversed ? track.scrollBar.width * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.width * track.scrollBar.nonAnimY * track.scrollBar.travelScale
Behavior on implicitHeight {
Anim {}
}
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
Behavior on implicitHeight {
Anim {}
}
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
MouseArea {
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
MouseArea {
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
}
}
+2 -3
View File
@@ -1,5 +1,4 @@
import QtQuick
import ZShell
import ZShell.Config
import qs.Services
@@ -16,9 +15,9 @@ ButtonBase {
const h = label.implicitHeight + padding * 2;
if (h % 2 !== 0)
return h + 1;
return ZUtils.snap(h, root);
return h;
}
implicitWidth: ZUtils.snap(implicitHeight, root)
implicitWidth: implicitHeight
inactiveColor: {
if (!isToggle && type === IconButton.Filled)
return Colors.palette.m3primary;
+1 -3
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -35,11 +34,10 @@ ButtonBase {
}
verticalPadding: Tokens.padding.extraSmall
SnapLayout {
RowLayout {
id: row
anchors.centerIn: parent
spacing: Tokens.spacing.small
MaterialIcon {
+66 -89
View File
@@ -1,8 +1,6 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtCanvas2D
import ZShell
Item {
id: root
@@ -38,62 +36,54 @@ Item {
property real fillAlpha: 0.15
property real lineWidth: 2
property real markerDotRadius: 4
property real labelFontSize: 8
property real labelFontSize: 10
Canvas2D {
Canvas {
id: canvas
anchors.fill: parent
alphaBlending: true
fillColor: "transparent"
renderStrategy: Canvas.Immediate
onWidthChanged: requestPaint()
onHeightChanged: requestPaint()
function snapV(v) {
return ZUtils.snap(v, canvas);
}
function strokeCurve(ctx, pts) {
ctx.beginPath();
ctx.moveTo(pts[0].x, pts[0].y);
const dpr = ZUtils.dprFor(canvas);
for (let i = 0; i < pts.length - 1; i++) {
const p1 = pts[i];
const p2 = pts[i + 1];
const [c1x, c1y, c2x, c2y] = segmentControls(pts, i);
if (root.curveSmoothing && pts.length > 2) {
const k = 1 / 6;
const n = pts.length;
const firstCol = Math.ceil(p1.x * dpr) + 1;
const lastCol = Math.floor(p2.x * dpr) - 1;
for (let col = firstCol; col <= lastCol; ++col) {
const x = col / dpr;
ctx.lineTo(x, bezierY(p1, c1x, c1y, c2x, c2y, p2, x));
for (let i = 0; i < n - 1; i++) {
const p0 = pts[Math.max(i - 1, 0)];
const p1 = pts[i];
const p2 = pts[i + 1];
const p3 = pts[Math.min(i + 2, n - 1)];
let c1x = p1.x + (p2.x - p0.x) * k;
let c1y = p1.y + (p2.y - p0.y) * k;
let c2x = p2.x - (p3.x - p1.x) * k;
let c2y = p2.y - (p3.y - p1.y) * k;
const minY = Math.min(p1.y, p2.y);
const maxY = Math.max(p1.y, p2.y);
c1y = Math.max(minY, Math.min(maxY, c1y));
c2y = Math.max(minY, Math.min(maxY, c2y));
ctx.bezierCurveTo(c1x, c1y, c2x, c2y, p2.x, p2.y);
}
} else {
for (let i = 0; i < pts.length - 1; i++) {
const p0 = pts[i];
const p1 = pts[i + 1];
const cx = (p0.x + p1.x) * 0.5;
ctx.bezierCurveTo(cx, p0.y, cx, p1.y, p1.x, p1.y);
}
ctx.lineTo(p2.x, p2.y);
}
}
function bezierY(p1, c1x, c1y, c2x, c2y, p2, targetX) {
let tlo = 0;
let thi = 1;
for (let it = 0; it < 16; it++) {
const tm = (tlo + thi) / 2;
const u = 1 - tm;
const x = u * u * u * p1.x + 3 * u * u * tm * c1x + 3 * u * tm * tm * c2x + tm * tm * tm * p2.x;
if (x < targetX)
tlo = tm;
else
thi = tm;
}
const t = (tlo + thi) / 2;
const u = 1 - t;
return u * u * u * p1.y + 3 * u * u * t * c1y + 3 * u * t * t * c2y + t * t * t * p2.y;
}
// Control points for segment i (pts[i] -> pts[i+1]), matching strokeCurve
function segmentControls(pts, i) {
const p0 = pts[Math.max(i - 1, 0)];
const p1 = pts[i];
@@ -119,6 +109,7 @@ Item {
return [cx, p1.y, cx, p2.y];
}
// Point on the curve at a given x (x is monotonic per segment)
function pointAtX(pts, targetX) {
let j = pts.length - 2;
for (let i = 0; i < pts.length - 1; i++) {
@@ -147,16 +138,10 @@ Item {
const t = (tlo + thi) / 2;
const u = 1 - t;
const y = u * u * u * p1.y + 3 * u * u * t * c1y + 3 * u * t * t * c2y + t * t * t * p2.y;
return {
x: targetX,
y
};
}
function cutPoint(pts, targetX) {
return pointAtX(pts, targetX);
return { x: targetX, y };
}
// Part of the curve left/right of a cut x, including the cut point
function cutLeft(pts, targetX) {
if (targetX <= pts[0].x)
return [];
@@ -173,7 +158,7 @@ Item {
const left = pts.slice(0, j + 1);
if (targetX > pts[j].x)
left.push(cutPoint(pts, targetX));
left.push(pointAtX(pts, targetX));
return left;
}
@@ -199,20 +184,17 @@ Item {
onPaint: {
const ctx = getContext("2d");
if (!ctx)
return;
ctx.reset();
ctx.clearRect(0, 0, width, height);
const W = width;
const H = height;
if (W < 2 || H < 2)
return;
const padLeft = root.labelFontSize * 5;
const padRight = 0;
const padTop = 0;
const padBottom = root.labelFontSize + 14;
const padLeft = root.labelFontSize * 3.4;
const padRight = 2;
const padTop = 2;
const padBottom = root.labelFontSize + 8;
const plot = {
x: padLeft,
y: padTop,
@@ -222,6 +204,8 @@ Item {
if (plot.w < 2 || plot.h < 2)
return;
// Auto-fit: NaN yMin/yMax derive from the data, snapped to the
// horizontal step grid, honoring minHorizontalLines
let lo = root.yMin;
let hi = root.yMax;
const loAuto = Number.isNaN(lo);
@@ -295,17 +279,11 @@ Item {
const xAt = i => plot.x + (i / root.xSteps) * plot.w;
const yAt = v => plot.y + (1 - (v - scaleBottom) / range) * plot.h;
const crisp = v => Math.floor(v) + 0.5;
const dpr = ZUtils.dprFor(canvas);
const devW = w => Math.max(1, Math.round(w * dpr));
const snapLine = (v, w) => {
const dw = devW(w);
return (Math.round(v * dpr - dw / 2) + dw / 2) / dpr;
};
const gridW = devW(1) / dpr;
// 1. Grid lines
ctx.strokeStyle = Qt.alpha(root.gridColor, root.gridAlpha);
ctx.lineWidth = gridW;
ctx.lineWidth = 1;
if (root.verticalLineStep > 0) {
for (let i = 0; i <= root.xSteps; i += root.verticalLineStep) {
@@ -314,7 +292,7 @@ Item {
if (i === root.xSteps && !root.lastXLine)
continue;
const x = snapLine(xAt(i), 1);
const x = crisp(xAt(i));
ctx.beginPath();
ctx.moveTo(x, plot.y);
ctx.lineTo(x, H);
@@ -322,11 +300,12 @@ Item {
}
}
// Lines extend down into yPaddingBottom, snapped to the grid
const vStart = lo - (root.yPaddingBottom > 0 ? Math.floor(root.yPaddingBottom / root.horizontalLineStep) * root.horizontalLineStep : 0);
if (root.horizontalLineStep > 0) {
for (let v = vStart; v <= hi + 0.001; v += root.horizontalLineStep) {
const y = snapLine(yAt(v), 1);
const y = crisp(yAt(v));
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(plot.x + plot.w, y);
@@ -334,8 +313,9 @@ Item {
}
}
// 2. Labels
ctx.fillStyle = Qt.alpha(root.labelColor, root.labelAlpha);
ctx.font = root.labelFontSize + "pt 'sans-serif'";
ctx.font = root.labelFontSize + "px sans-serif";
ctx.textAlign = "left";
ctx.textBaseline = "top";
@@ -348,7 +328,7 @@ Item {
const text = root.xLabel(i);
if (text)
ctx.fillText(text, xAt(i) + 4, plot.y + plot.h + 8);
ctx.fillText(text, xAt(i) + 4, plot.y + plot.h + 4);
}
}
@@ -361,6 +341,7 @@ Item {
}
}
// 3. Curve, split into segments at null gaps
const segments = [];
let current = null;
for (let i = 0; i < series.length; i++) {
@@ -371,7 +352,7 @@ Item {
continue;
}
const pt = {
x: snapV(xAt(i)),
x: xAt(i),
y: yAt(series[i])
};
if (!current)
@@ -388,6 +369,8 @@ Item {
const markerPx = hasMarker ? xAt(root.markerX) : 0;
let gapPx = 0;
if (hasMarker) {
// markerGap is measured from the dot edge, perpendicular to the
// curve; project onto x via the local curve slope
let slope = 0;
const seg = segments.find(s => s[0].x <= markerPx && markerPx <= s[s.length - 1].x);
if (seg && seg.length > 2 && markerPx - 1 >= seg[0].x && markerPx + 1 <= seg[seg.length - 1].x)
@@ -399,6 +382,7 @@ Item {
if (seg.length < 2)
continue;
// Fill stays continuous under the marker
ctx.fillStyle = Qt.alpha(root.lineColor, root.fillAlpha);
strokeCurve(ctx, seg);
ctx.lineTo(seg[seg.length - 1].x, plot.y + plot.h);
@@ -406,6 +390,7 @@ Item {
ctx.closePath();
ctx.fill();
// Stroke has a gap around the marker
const pieces = hasMarker ? [cutLeft(seg, markerPx - gapPx), cutRight(seg, markerPx + gapPx)] : [seg];
for (const pts of pieces) {
@@ -413,32 +398,24 @@ Item {
continue;
ctx.strokeStyle = root.lineColor;
ctx.lineWidth = ZUtils.snap(root.lineWidth, root);
ctx.lineWidth = root.lineWidth;
strokeCurve(ctx, pts);
ctx.stroke();
}
}
// 4. Marker: dashed vertical + dot
if (root.markerX >= 0 && root.markerX <= root.xSteps) {
const x = markerPx;
ctx.setLineDash([4, 4]);
ctx.strokeStyle = Qt.alpha(root.markerColor, 0.6);
ctx.lineWidth = gridW;
const lineX = snapLine(x, 1);
let dashY = plot.y;
let dashOn = true;
while (dashY < H) {
const dashEnd = Math.min(dashY + 4, H);
if (dashOn) {
ctx.beginPath();
ctx.moveTo(lineX, snapV(dashY));
ctx.lineTo(lineX, snapV(dashEnd));
ctx.stroke();
}
dashY = dashEnd;
dashOn = !dashOn;
}
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(crisp(x), plot.y);
ctx.lineTo(crisp(x), H);
ctx.stroke();
ctx.setLineDash([]);
const i0 = Math.floor(root.markerX);
const v0 = series[i0];
@@ -453,7 +430,7 @@ Item {
if (y != null) {
ctx.fillStyle = root.markerColor;
ctx.beginPath();
ctx.circle(snapV(x), y, root.markerDotRadius);
ctx.arc(x, y, root.markerDotRadius, 0, Math.PI * 2);
ctx.fill();
}
}
+7 -9
View File
@@ -4,7 +4,6 @@ import QtQuick
import QtQuick.Layouts
import Quickshell
import ZShell.Config
import ZShell.Components
import qs.Drawers
import qs.Services
@@ -35,7 +34,7 @@ MouseArea {
cursorShape: expanded ? Qt.ArrowCursor : undefined
enabled: expanded
hoverEnabled: expanded
layer.enabled: false
layer.enabled: opacity < 1
opacity: expanded ? 1 : 0
parent: {
const win = QsWindow.window;
@@ -102,7 +101,8 @@ MouseArea {
yScale: root.expanded ? 1 : 0.1
Behavior on yScale {
Anim {}
Anim {
}
}
}
@@ -111,14 +111,12 @@ MouseArea {
color: Colors.palette.m3surfaceContainerLow
radius: parent.radius
SnapLayout {
ColumnLayout {
id: column
anchors.fill: parent
anchors.margins: Tokens.padding.extraSmall
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
Repeater {
id: repeater
@@ -139,7 +137,8 @@ MouseArea {
radius: menu.radius - column.anchors.margins
Behavior on radius {
Anim {}
Anim {
}
}
StateLayer {
@@ -154,12 +153,11 @@ MouseArea {
}
}
SnapLayout {
RowLayout {
id: menuOptionRow
anchors.fill: parent
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.small
MaterialIcon {
+1 -2
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -54,7 +53,7 @@ Row {
onClicked: root.active?.clicked()
}
SnapLayout {
RowLayout {
id: textRow
anchors.centerIn: parent
+1 -1
View File
@@ -12,7 +12,7 @@ TextField {
implicitHeight: contentHeight + topPadding + bottomPadding
implicitWidth: contentWidth + leftPadding + rightPadding
placeholderTextColor: Colors.palette.m3onSurfaceVariant // No anim cause placeholder is custom
renderType: TextField.QtRendering
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
selectedTextColor: color
selectionColor: Qt.alpha(Colors.palette.m3primary, 0.4)
verticalAlignment: TextInput.AlignVCenter
+2 -5
View File
@@ -1,5 +1,4 @@
import ZShell
import ZShell.Components
import QtQuick
import QtQuick.Layouts
import qs.Components
@@ -48,7 +47,7 @@ CustomRect {
z: -1
}
SnapLayout {
RowLayout {
id: layout
anchors.fill: parent
@@ -89,11 +88,9 @@ CustomRect {
}
}
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: 0
orientation: Qt.Vertical
CustomText {
id: title
-3
View File
@@ -1,7 +1,6 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.Effects
CustomFlickable {
@@ -10,7 +9,6 @@ CustomFlickable {
property real bottomFadeOpacity: fadeShouldBeActive(false) ? 0 : 1
property real fadeAmount: 0.1
property real topFadeOpacity: fadeShouldBeActive(true) ? 0 : 1
readonly property real dpr: Math.ceil((QsWindow.window as QsWindow)?.devicePixelRatio ?? 1)
function fadeShouldBeActive(isStart: bool): bool {
// When content is smaller than flickable size, hide fade when rebound starts
@@ -30,7 +28,6 @@ CustomFlickable {
type: Anim.SlowEffects
}
}
layer.textureSize: Qt.size(width * dpr, height * dpr)
layer.effect: Mask {
maskSource: mask
+39 -41
View File
@@ -2,57 +2,55 @@ import QtQuick
import ZShell.Config
import qs.Services
Item {
CustomClippingRect {
id: track
required property var scrollBar
required property var mouseArea
ClipRect {
anchors.bottom: parent.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.top: parent.top
implicitWidth: handle.implicitWidth
radius: Tokens.rounding.full
CustomRect {
id: handle
anchors.right: parent.right
anchors.top: parent.top
radius: Tokens.rounding.full
implicitWidth: handle.implicitWidth
CustomRect {
id: handle
anchors.right: parent.right
color: Colors.palette.m3secondary
implicitHeight: track.scrollBar.height * track.scrollBar.effectiveSize
implicitWidth: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
opacity: {
if (!track.scrollBar.enabled)
return 0;
if (track.scrollBar.size === 1)
return 0;
if (track.mouseArea.pressed)
return 1;
if (track.mouseArea.containsMouse)
return 0.8;
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
return 0.6;
color: Colors.palette.m3secondary
implicitHeight: track.scrollBar.height * track.scrollBar.effectiveSize
implicitWidth: track.mouseArea.pressed || track.mouseArea.containsMouse ? Tokens.padding.extraSmall * 2 : Tokens.padding.extraSmall
opacity: {
if (!track.scrollBar.enabled)
return 0;
}
radius: Tokens.rounding.full
y: track.scrollBar.reversed ? track.scrollBar.height * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.height * track.scrollBar.nonAnimY * track.scrollBar.travelScale
if (track.scrollBar.size === 1)
return 0;
if (track.mouseArea.pressed)
return 1;
if (track.mouseArea.containsMouse)
return 0.8;
if (track.scrollBar.policy === CustomScrollBar.AlwaysOn || track.scrollBar.shouldBeActive)
return 0.6;
return 0;
}
radius: Tokens.rounding.full
y: track.scrollBar.reversed ? track.scrollBar.height * (1 + track.scrollBar.nonAnimY) * track.scrollBar.travelScale : track.scrollBar.height * track.scrollBar.nonAnimY * track.scrollBar.travelScale
Behavior on implicitWidth {
Anim {}
}
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
Behavior on implicitWidth {
Anim {}
}
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
MouseArea {
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
MouseArea {
acceptedButtons: Qt.NoButton
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
}
}
}
+9 -1
View File
@@ -43,6 +43,13 @@ Scope {
hasBar: root.geometry.barOnBottom
}
Timer {
interval: 5000
running: true
onTriggered: console.log("top height:", top.exclusiveZone, "left width:", left.exclusiveZone, "right width:", right.exclusiveZone, "bottom height:", bottom.exclusiveZone)
}
component ExclusionZone: CustomWindow {
property bool hasBar
@@ -52,6 +59,7 @@ Scope {
name: "Bar-Exclusion"
screen: root.screen
mask: Region {}
mask: Region {
}
}
}
+16 -26
View File
@@ -1,12 +1,10 @@
import Quickshell
import QtQuick
import ZShell.Config
import ZShell
import qs.Components
import qs.Modules.Bar.Popouts as Popouts
import qs.Modules.Notifications as Notifications
import qs.Modules.Sidebar as Sidebar
import qs.Modules.Sidebar.Utils as Utils
import qs.Modules.Notifications.Sidebar as Sidebar
import qs.Modules.Notifications.Sidebar.Utils as Utils
import qs.Modules.Dashboard as Dashboard
import qs.Modules.Osd as Osd
import qs.Components.Toast as Toasts
@@ -16,15 +14,20 @@ import qs.Modules.Settings as Settings
import qs.Modules.Drawing as Drawing
import qs.Modules.Dock as Dock
import qs.Modules.Clipboard as Clipboard
import ZShell.Config
Item {
id: root
required property Item bar
required property real borderThickness
readonly property alias clipboard: clipboard
readonly property alias dashboard: dashboard
readonly property alias dashboardWrapper: dashboardWrapper
readonly property alias dock: dock
readonly property alias drawing: drawing
required property var drawingItem
required property EdgeGeometry geometry
readonly property alias launcher: launcher
readonly property alias notifications: notifications
readonly property alias osd: osd
@@ -33,19 +36,14 @@ Item {
readonly property alias popoutsWrapper: popouts
readonly property alias resources: resources
readonly property alias resourcesWrapper: resourcesWrapper
required property ShellScreen screen
required property ScreenState screenState
readonly property alias settings: settings
readonly property alias settingsWrapper: settingsWrapper
readonly property alias sidebar: sidebar
readonly property alias toasts: toasts
readonly property alias utilities: utilities
required property Item bar
required property real borderThickness
required property var drawingItem
required property EdgeGeometry geometry
required property ShellScreen screen
required property ScreenState screenState
anchors.bottomMargin: geometry.insetBottom(borderThickness)
anchors.fill: parent
anchors.leftMargin: geometry.insetLeft(borderThickness)
@@ -75,10 +73,7 @@ Item {
anchors.right: parent.right
anchors.rightMargin: sidebar.width * (1 - sidebar.offsetScale)
y: ZUtils.snap((parent.height - implicitHeight) / 2, root)
// anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenter: parent.verticalCenter
clip: sidebar.visible
implicitHeight: osd.implicitHeight
implicitWidth: osd.implicitWidth * (1 - osd.offsetScale)
@@ -86,7 +81,8 @@ Item {
Osd.Wrapper {
id: osd
anchors.fill: parent
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
screen: root.screen
screenState: root.screenState
sidebarOrSessionVisible: sidebar.visible
@@ -132,9 +128,8 @@ Item {
Launcher.Wrapper {
id: launcher
x: ZUtils.snap((parent.width - implicitWidth) / 2, root)
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
panels: root
screen: root.screen
screenState: root.screenState
@@ -154,10 +149,8 @@ Item {
property real offsetScale: dashboard.shouldBeActive ? 0 : 1
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
x: ZUtils.snap((parent.width - implicitWidth) / 2, dashboardWrapper)
clip: offsetScale > 0
implicitHeight: dashboard.implicitHeight * (1 - offsetScale)
implicitWidth: dashboard.implicitWidth
@@ -196,11 +189,8 @@ Item {
Settings.Wrapper {
id: settings
x: ZUtils.snap((parent.width - implicitWidth) / 2, settings)
y: ZUtils.snap((parent.height - implicitHeight) / 2 - (implicitHeight + 5 + (parent.height - implicitHeight) / 2) * offsetScale, settings)
// anchors.centerIn: parent
// anchors.verticalCenterOffset: (-implicitHeight - 5 - ((root.height - implicitHeight) / 2)) * offsetScale
anchors.centerIn: parent
anchors.verticalCenterOffset: (-implicitHeight - 5 - ((root.height - implicitHeight) / 2)) * offsetScale
panels: root
screen: root.screen
screenState: root.screenState
+1
View File
@@ -11,6 +11,7 @@ import ZShell.Blobs
import qs.Daemons
import qs.Components
import qs.Modules.Bar
import qs.Modules.Bar.Popouts.Network as N
import ZShell.Config
import qs.Helpers
import qs.Drawers
+31 -18
View File
@@ -3,12 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import qs.Services
SnapLayout {
ColumnLayout {
id: root
readonly property real centerScale: Math.min(1, screenHeight / 1440)
@@ -19,32 +18,36 @@ SnapLayout {
Layout.fillHeight: true
Layout.fillWidth: false
Layout.preferredWidth: centerWidth
orientation: Qt.Vertical
spacing: Tokens.spacing.largeIncreased * 2
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Tokens.spacing.small
CustomText {
Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3secondary
font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build()
font.bold: true
font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: Time.hourStr
}
CustomText {
Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3primary
font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build()
font.bold: true
font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: ":"
}
CustomText {
Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3secondary
font: Tokens.font.headline.builders.large.scale(3 * root.centerScale).weight(Font.Bold).width(30).build()
font.bold: true
font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: Time.minuteStr
}
}
@@ -53,11 +56,13 @@ SnapLayout {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: -Tokens.padding.large * 2
color: Colors.palette.m3tertiary
font: Tokens.font.title.builders.medium.weight(Font.DemiBold).build()
font.bold: true
font.family: Config.appearance.font.family.mono
font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale)
text: Time.format("dddd, d MMMM yyyy")
}
ClipRect {
CustomClippingRect {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Tokens.spacing.largeIncreased * 2
color: Colors.tPalette.m3surfaceContainer
@@ -68,7 +73,7 @@ SnapLayout {
MaterialIcon {
anchors.centerIn: parent
color: Colors.palette.m3onSurfaceVariant
fontStyle: Tokens.font.icon.size(root.centerWidth / 4).build()
font.pointSize: Math.floor(root.centerWidth / 4)
text: "person"
}
@@ -83,7 +88,9 @@ SnapLayout {
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.body.large
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.normal
font.weight: 600
text: root.greeter.username
visible: text.length > 0
}
@@ -119,7 +126,7 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: input
anchors.fill: parent
@@ -148,7 +155,8 @@ SnapLayout {
}
Behavior on opacity {
Anim {}
Anim {
}
}
}
@@ -183,6 +191,7 @@ SnapLayout {
anchors.centerIn: parent
color: root.greeter.buffer && !root.greeter.launching ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
font.weight: 500
text: root.greeter.launching ? "hourglass_top" : "arrow_forward"
}
}
@@ -195,7 +204,8 @@ SnapLayout {
implicitHeight: Math.max(message.implicitHeight, stateMessage.implicitHeight)
Behavior on implicitHeight {
Anim {}
Anim {
}
}
CustomText {
@@ -235,10 +245,12 @@ SnapLayout {
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Behavior on opacity {
Anim {}
Anim {
}
}
Behavior on scale {
Anim {}
Anim {
}
}
onMsgChanged: {
@@ -280,7 +292,8 @@ SnapLayout {
anchors.left: parent.left
anchors.right: parent.right
color: isError ? Colors.palette.m3error : Colors.palette.m3primary
font: Tokens.font.mono.medium
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
horizontalAlignment: Qt.AlignHCenter
opacity: 0
scale: 0.7
+1 -1
View File
@@ -20,7 +20,7 @@ BusyIndicator {
property int animState
property color bgColor: Colors.palette.m3secondaryContainer
property color fgColor: Colors.palette.m3primary
property real implicitSize: Tokens.font.body.medium.pointSize * 3
property real implicitSize: Tokens.font.size.normal * 3
property real internalStrokeWidth: strokeWidth
readonly property alias progress: manager.progress
property real strokeWidth: Tokens.padding.extraSmall * 0.8
-41
View File
@@ -1,41 +0,0 @@
import QtQuick
import ZShell.Components
Item {
id: root
property real radius
property real topLeftRadius: radius
property real topRightRadius: radius
property real bottomRightRadius: radius
property real bottomLeftRadius: radius
property color color: "transparent"
default property alias contentData: contentItem.data
Item {
id: contentItem
anchors.fill: parent
}
ShaderEffectSource {
id: source
hideSource: true
sourceItem: contentItem
}
RoundedMask {
anchors.fill: parent
source: source
topLeftRadius: root.topLeftRadius
topRightRadius: root.topRightRadius
bottomRightRadius: root.bottomRightRadius
bottomLeftRadius: root.bottomLeftRadius
color: root.color
}
Behavior on color {
CAnim {}
}
}
-23
View File
@@ -1,36 +1,13 @@
import QtQuick
import qs.Services
Flickable {
id: root
property bool doneFakeFlick
interactive: !ShellState.forActive().isDrawing
maximumFlickVelocity: 3000
rebound: Transition {
onRunningChanged: {
if (!running && !root.doneFakeFlick) {
root.doneFakeFlick = true;
root.flick(1, 1);
root.flick(-1, -1);
Qt.callLater(() => root.cancelFlick());
}
}
Anim {
properties: "x,y"
}
}
Timer {
interval: 10
running: root.doneFakeFlick
onTriggered: {
root.doneFakeFlick = false;
root.returnToBounds();
}
}
}
-23
View File
@@ -1,36 +1,13 @@
import QtQuick
import qs.Services
ListView {
id: root
property bool doneFakeFlick
interactive: !ShellState.forActive()?.isDrawing
maximumFlickVelocity: 3000
rebound: Transition {
// onRunningChanged: {
// if (!running && !root.doneFakeFlick) {
// root.doneFakeFlick = true;
// root.flick(1, 1);
// root.flick(-1, -1);
// Qt.callLater(() => root.cancelFlick());
// }
// }
Anim {
properties: "x,y"
type: Anim.DefaultEffects
}
}
// Timer {
// interval: 10
// running: root.doneFakeFlick
//
// onTriggered: {
// root.doneFakeFlick = false;
// }
// }
}
-1
View File
@@ -4,7 +4,6 @@ MouseArea {
property int scrollAccumulatedY: 0
function onWheel(event: WheelEvent): void {
event.accepted = false;
}
onWheel: event => {
+2 -1
View File
@@ -6,6 +6,7 @@ Rectangle {
color: "transparent"
Behavior on color {
CAnim {}
CAnim {
}
}
}
+7 -9
View File
@@ -14,9 +14,10 @@ Text {
property real animateTo: 1
color: Colors.palette.m3onSurface
font: Tokens.font.body.small
font.family: Config.appearance.font.family.sans
font.pointSize: Tokens.font.size.normal
linkColor: Colors.palette.m3onPrimaryFixedVariant
renderType: Text.QtRendering
renderType: Text.NativeRendering
textFormat: Text.PlainText
Behavior on color {
@@ -27,25 +28,22 @@ Text {
enabled: root.animate
SequentialAnimation {
TAnim {
target: root
Anim {
to: root.animateFrom
type: Anim.FastEffects
}
PropertyAction {
}
TAnim {
target: root
Anim {
to: root.animateTo
type: Anim.DefaultEffects
}
}
}
component TAnim: Anim {
component Anim: NumberAnimation {
duration: root.animateDuration / 2
easing.type: Easing.BezierSpline
properties: root.animateProp.split(",").length > 1 ? root.animateProp : ""
property: root.animateProp.split(",").length === 1 ? root.animateProp : ""
target: root
+52 -281
View File
@@ -1,305 +1,76 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Shapes
import QtQuick.Controls
import ZShell.Config
import qs.Services
TextFieldBase {
TextField {
id: root
enum TextFieldType {
Outlined,
Filled
}
background: null
color: Colors.palette.m3onSurface
cursorVisible: !readOnly
font.family: Config.appearance.font.family.sans
font.pointSize: Tokens.font.size.smaller
placeholderTextColor: Colors.palette.m3outline
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
readonly property int clampedRadius: Math.min(horizontalPadding, Math.min(width, height) / 2, radius)
readonly property string effectiveSupportingText: isError && errorText ? errorText : supportingText
readonly property int filledOffset: type === CustomTextField.Filled ? Tokens.spacing.small : 0
readonly property int leadingOffset: leadingIcon ? leadingIconLoader.width + leadingIconLoader.anchors.leftMargin : 0
readonly property real smallFontScale: smallFontSize / font.pointSize
readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Tokens.spacing.extraSmall : 0
readonly property int trailingOffset: trailingIcon ? trailingIconLoader.width + trailingIconLoader.anchors.rightMargin : 0
readonly property bool valid: !validate || (!text && emptyIsValid) || (validate instanceof RegExp ? validate.test(text) : !!validate(text))
property int horizontalPadding: Tokens.padding.large
property int verticalPadding: Tokens.padding.large
property int radius: Tokens.rounding.small
property string supportingText
property string trailingIcon
property int smallFontSize: Tokens.font.label.small.pointSize
property int type: CustomTextField.Outlined
property var validate // Regex or function
property bool emptyIsValid: true
property string errorText
property bool isError
property string leadingIcon
bottomPadding: verticalPadding + supportingTextOffset - filledOffset
leftPadding: horizontalPadding + leadingOffset
rightPadding: horizontalPadding + trailingOffset
topPadding: verticalPadding + filledOffset
background: Loader {
anchors.bottomMargin: root.supportingTextOffset
anchors.fill: parent
sourceComponent: root.type === CustomTextField.Filled ? filledComp : outlineComp
StateLayer {
id: stateLayer
cursorShape: Qt.IBeamCursor
enabled: !root.activeFocus
manualPressOverride: tapHandler.pressed
radius: root.type === CustomTextField.Outlined ? root.clampedRadius : 0
topLeftRadius: root.clampedRadius
topRightRadius: root.clampedRadius
onClicked: root.focus = true
Behavior on color {
CAnim {
}
}
cursorDelegate: CustomRect {
id: cursor
onEditingFinished: {
if (!valid)
isError = true;
}
onPressed: {
if (stateLayer.enabled)
stateLayer.press(stateLayer.mouseX, stateLayer.mouseY);
}
onTextEdited: {
if (isError)
isError = false;
}
property bool disableBlink
Item {
id: contentWrapper
color: Colors.palette.m3primary
implicitWidth: 2
radius: Tokens.rounding.medium
anchors.bottomMargin: root.supportingTextOffset
anchors.fill: parent
CustomText {
id: placeholder
anchors.left: parent.left
anchors.leftMargin: root.leftPadding
anchors.topMargin: Tokens.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter
color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : root.text ? Colors.palette.m3outline : root.placeholderTextColor)
font.family: root.font.family
font.pointSize: root.font.pointSize
font.variableAxes: root.font.variableAxes
font.weight: root.font.weight
renderType: Text.QtRendering
text: root.placeholderText
states: [
State {
name: "smallOutlined"
when: root.type === CustomTextField.Outlined && (root.activeFocus || root.text)
PropertyChanges {
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding
placeholder.scale: root.smallFontScale
}
AnchorChanges {
anchors.verticalCenter: contentWrapper.top
target: placeholder
}
},
State {
name: "smallFilled"
when: root.type === CustomTextField.Filled && (root.activeFocus || root.text)
PropertyChanges {
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + root.leadingOffset
placeholder.scale: root.smallFontScale
}
AnchorChanges {
anchors.top: contentWrapper.top
anchors.verticalCenter: undefined
target: placeholder
}
}
]
transitions: Transition {
Anim {
properties: "scale,leftMargin"
type: Anim.DefaultEffects
}
AnchorAnim {
duration: Tokens.anim.durations.expressiveDefaultEffects
easing: Tokens.anim.expressiveDefaultEffects
}
Behavior on opacity {
Anim {
duration: Tokens.anim.durations.small
}
}
Loader {
id: leadingIconLoader
active: root.leadingIcon
anchors.left: parent.left
anchors.leftMargin: Tokens.padding.small
anchors.verticalCenter: parent.verticalCenter
sourceComponent: MaterialIcon {
color: Colors.palette.m3onSurfaceVariant
text: root.leadingIcon
fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build()
}
}
Loader {
id: trailingIconLoader
active: root.trailingIcon
anchors.right: parent.right
anchors.rightMargin: Tokens.padding.small
anchors.verticalCenter: parent.verticalCenter
sourceComponent: MaterialIcon {
color: Colors.palette.m3onSurfaceVariant
text: root.trailingIcon
fontStyle: Tokens.font.icon.builders.medium.scale(0.9).build()
}
}
}
Loader {
id: supportingTextLoader
active: root.effectiveSupportingText
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: root.horizontalPadding
sourceComponent: CustomText {
color: root.isError ? Colors.palette.m3error : Colors.palette.m3onSurfaceVariant
font: Tokens.font.label.small
text: root.effectiveSupportingText
}
}
TapHandler {
id: tapHandler
}
Component {
id: outlineComp
Shape {
id: bg
asynchronous: true
preferredRendererType: Shape.CurveRenderer
ShapePath {
id: path
readonly property real inset: strokeWidth / 2
readonly property real outlineGap: placeholder.width * root.smallFontScale + Tokens.spacing.small * 2
property real outlineGapScale: root.activeFocus || root.text ? 1 : 0
capStyle: ShapePath.RoundCap
fillColor: "transparent"
startX: path.inset + root.horizontalPadding - root.clampedRadius + path.outlineGap * (1 - path.outlineGapScale) / 2 + path.outlineGap * path.outlineGapScale
startY: path.inset
strokeColor: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline)
strokeWidth: root.activeFocus ? 2 : 1
Behavior on outlineGapScale {
Anim {
type: Anim.DefaultEffects
}
}
Behavior on strokeColor {
CAnim {}
}
Behavior on strokeWidth {
Anim {}
}
PathLine {
x: bg.width - path.inset - root.clampedRadius
y: path.inset
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: bg.width - path.inset
y: path.inset + root.clampedRadius
}
PathLine {
x: bg.width - path.inset
y: bg.height - path.inset - root.clampedRadius
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: bg.width - path.inset - root.clampedRadius
y: bg.height - path.inset
}
PathLine {
x: path.inset + root.clampedRadius
y: bg.height - path.inset
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: path.inset
y: bg.height - path.inset - root.clampedRadius
}
PathLine {
x: path.inset
y: path.inset + root.clampedRadius
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: path.inset + root.clampedRadius
y: path.inset
}
PathLine {
x: path.inset + root.horizontalPadding - root.clampedRadius / 2 + path.outlineGap * (1 - path.outlineGapScale) / 2
y: path.inset
Connections {
function onCursorPositionChanged(): void {
if (root.activeFocus && root.cursorVisible) {
cursor.opacity = 1;
cursor.disableBlink = true;
enableBlink.restart();
}
}
target: root
}
Timer {
id: enableBlink
interval: 100
onTriggered: cursor.disableBlink = false
}
Timer {
interval: 500
repeat: true
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
triggeredOnStart: true
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
}
Binding {
cursor.opacity: 0
when: !root.activeFocus || !root.cursorVisible
}
}
Component {
id: filledComp
CustomRect {
color: root.activeFocus ? Colors.tPalette.m3surfaceContainerHighest : Colors.tPalette.m3surfaceContainerHigh
topLeftRadius: root.clampedRadius
topRightRadius: root.clampedRadius
CustomRect {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: root.isError ? Colors.palette.m3error : (root.activeFocus ? Colors.palette.m3primary : Colors.palette.m3outline)
implicitHeight: root.activeFocus ? 2 : 1
Behavior on implicitHeight {
Anim {}
}
}
Behavior on placeholderTextColor {
CAnim {
}
}
}
+2 -3
View File
@@ -1,16 +1,15 @@
import QtQuick
import QtQuick.Controls
import ZShell.Config
import qs.Services
TextInput {
renderType: Text.NativeRendering
selectedTextColor: Colors.palette.m3onSecondaryContainer
selectionColor: Colors.tPalette.colSecondaryContainer
selectionColor: Colors.tPalette.m3onSecondaryContainer
font {
family: Config.appearance?.font.family.sans ?? "sans-serif"
hintingPreference: Font.PreferFullHinting
pixelSize: Config.appearance?.font.size.normal ?? 15
pixelSize: Tokens?.font.size.normal ?? 15
}
}
-79
View File
@@ -1,79 +0,0 @@
import QtQuick
import Quickshell
import ZShell.Config
Image {
id: root
property int fadeInAnim: Anim.DefaultEffects
property int fadeInLargeAnim: Anim.StandardLarge
property int fadeOutAnim: Anim.FastEffects
property bool fadingOut
property bool hadPrevious
property bool preventInit
function maybeStartInAnim(): void {
if (!preventInit && !opacityInAnim.running && status === Image.Ready) {
opacityInAnim.type = hadPrevious ? fadeInAnim : fadeInLargeAnim;
opacityInAnim.start();
}
}
asynchronous: true
fillMode: Image.PreserveAspectCrop
opacity: 0
retainWhileLoading: true
sourceSize: {
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
return Qt.size(width * dpr, height * dpr);
}
Anim on opacity {
id: opacityInAnim
running: false
to: 1
}
Behavior on source {
SequentialAnimation {
ScriptAction {
script: opacityInAnim.stop()
}
PropertyAction {
property: "fadingOut"
target: root
value: true
}
Anim {
property: "opacity"
target: root
to: 0
type: root.fadeOutAnim
}
PropertyAction {
property: "fadingOut"
target: root
value: false
}
PropertyAction {
property: "hadPrevious"
target: root
value: root.source
}
PropertyAction {
}
ScriptAction {
script: root.maybeStartInAnim()
}
}
}
onPreventInitChanged: maybeStartInAnim()
onStatusChanged: maybeStartInAnim()
}
-115
View File
@@ -1,115 +0,0 @@
import QtQuick
import Quickshell
import M3Shapes
import ZShell.Config
import qs.Services
MaterialShape {
id: root
property bool animated: true
property real cRotation
property bool containsIcon
property real dampingRatio: 0.6
property real lRotation
property int morphAnimRotation: 60
property real morphScale: 0.14
property alias rotateAnimDuration: rotateAnim.duration
property int shapeIndex
property list<int> shapes: {
if (containsIcon)
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
return [MaterialShape.SoftBurst, MaterialShape.Cookie9Sided, MaterialShape.Pentagon, MaterialShape.Pill, MaterialShape.Sunny, MaterialShape.Cookie4Sided, MaterialShape.Oval];
}
readonly property real springDuration: {
const wn = Math.sqrt(stiffness);
const r = -dampingRatio * wn;
const c = 1 / Math.sqrt(1 - dampingRatio * dampingRatio);
return Math.log(visibilityThreshold / c) / r;
}
readonly property real springMaxVelocity: {
const wn = Math.sqrt(stiffness);
const factor = Math.exp(-z * Math.acos(z) / Math.sqrt(1 - z * z));
return wn * factor;
}
property bool springSettled: true
property real stiffness: 180
property real thisLRotation
property real visibilityThreshold: 0.075
function spring(t: real): var {
const wn = Math.sqrt(stiffness);
const za = dampingRatio * wn;
const wd = wn * Math.sqrt(1 - dampingRatio * dampingRatio);
const r = za / wd;
const pos = 1 - Math.exp(-za * t) * (Math.cos(wd * t) + r * Math.sin(wd * t));
const vel = Math.exp(-za * t) * (wn * wn / wd) * Math.sin(wd * t);
return [pos, vel];
}
color: Colors.palette.m3primary
implicitSize: 38
toShape: shapes[0]
RotationAnimation on cRotation {
id: rotateAnim
duration: 4666
easing.type: Easing.Linear
from: 0
loops: Animation.Infinite
running: root.animated
to: 360
}
Behavior on color {
CAnim {
}
}
ElapsedTimer {
id: timer
}
FrameAnimation {
running: root.animated && !root.springSettled
onTriggered: {
const t = timer.elapsed();
if (t >= root.springDuration) {
root.springSettled = true;
} else {
const [pos, vel] = root.spring(t);
root.morphProgress = Math.min(1, pos); // Overshooting the morph looks weird
root.thisLRotation = pos * root.morphAnimRotation;
root.scale = 1 + vel * root.morphScale / root.springMaxVelocity;
}
}
}
Timer {
interval: 650
repeat: true
running: root.animated
triggeredOnStart: true
onTriggered: {
root.beginBatchUpdate();
root.fromShape = root.toShape;
root.shapeIndex = (root.shapeIndex + 1) % root.shapes.length;
root.toShape = root.shapes[root.shapeIndex];
root.morphProgress = 0;
root.rotation = root.rotation;
root.lRotation = (root.lRotation + root.thisLRotation) % 360;
root.thisLRotation = 0;
root.rotation = Qt.binding(() => root.cRotation + root.lRotation + root.thisLRotation);
root.springSettled = false;
timer.restart();
root.endBatchUpdate();
}
}
}
+9 -7
View File
@@ -1,14 +1,16 @@
import QtQuick
import ZShell.Config
import qs.Services
CustomText {
id: root
property real fill: 0
property real fill
property int grade: Colors.light ? 0 : -25
property font fontStyle: Tokens.font.icon.small
renderType: Text.NativeRendering
font: Tokens.font.icon.size(fontStyle.pointSize).weight(fontStyle.weight).vaxes(fontStyle.variableAxes).fill(fill.toFixed(1)).grade(grade).build()
font.family: "Material Symbols Rounded"
font.pointSize: Tokens.font.size.larger
font.variableAxes: ({
FILL: fill.toFixed(1),
GRAD: grade,
opsz: fontInfo.pixelSize,
wght: fontInfo.weight
})
}
+8 -6
View File
@@ -1,6 +1,8 @@
import QtQuick
import QtQuick.Shapes
import ZShell
import ZShell.Components
import qs.Helpers
import ZShell.Config
import qs.Services
@@ -11,6 +13,7 @@ MouseArea {
property alias bottomRightRadius: base.bottomRightRadius
property real circleRadius
property alias color: base.color
property bool disabled
readonly property real endRadius: {
const d1 = distSq(0, 0);
const d2 = distSq(width, 0);
@@ -19,7 +22,6 @@ MouseArea {
return (Math.sqrt(Math.max(d1, d2, d3, d4)) + (shapeMorph ? 24 : 0)) * 1.3;
}
property real endRadiusAtPress
property bool manualHoverOverride
property bool manualPressOverride
property real pressX: width / 2
property real pressY: height / 2
@@ -27,7 +29,7 @@ MouseArea {
readonly property alias rect: base
property bool shapeMorph
property bool showHoverBackground: true
property real stateOpacity: containsMouse || manualHoverOverride ? 0.08 : 0
property real stateOpacity: containsMouse ? 0.08 : 0
property alias topLeftRadius: base.topLeftRadius
property alias topRightRadius: base.topRightRadius
@@ -50,8 +52,8 @@ MouseArea {
}
anchors.fill: parent
cursorShape: !enabled ? undefined : Qt.PointingHandCursor
enabled: parent.enabled
cursorShape: disabled ? undefined : Qt.PointingHandCursor
enabled: !disabled
hoverEnabled: true
Behavior on stateOpacity {
@@ -98,13 +100,13 @@ MouseArea {
id: base
anchors.fill: parent
bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0
bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0
color: Colors.palette.m3onSurface
opacity: root.stateOpacity
// Pick up radius from parent if it has one (parent can be anything with radius props)
// qmllint disable missing-property
radius: root.parent?.radius ?? 0
bottomLeftRadius: root.parent?.bottomLeftRadius ?? radius ?? 0
bottomRightRadius: root.parent?.bottomRightRadius ?? radius ?? 0
topLeftRadius: root.parent?.topLeftRadius ?? radius ?? 0
topRightRadius: root.parent?.topRightRadius ?? radius ?? 0
// qmllint enable missing-property
+41 -19
View File
@@ -1,12 +1,11 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import ZShell.Config
import qs.Services
SnapLayout {
RowLayout {
id: root
required property var greeter
@@ -14,16 +13,34 @@ SnapLayout {
spacing: Tokens.spacing.largeIncreased * 2
CustomRect {
Layout.fillHeight: true
ColumnLayout {
Layout.fillWidth: true
topLeftRadius: Tokens.rounding.largeIncreased
bottomLeftRadius: Tokens.rounding.largeIncreased
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
spacing: Tokens.spacing.medium
UserDock {
greeter: root.greeter
CustomRect {
Layout.fillWidth: true
color: Colors.tPalette.m3surfaceContainer
implicitHeight: weather.implicitHeight
radius: Tokens.rounding.small
topLeftRadius: Tokens.rounding.largeIncreased
WeatherInfo {
id: weather
rootHeight: root.height
}
}
CustomClippingRect {
Layout.fillHeight: true
Layout.fillWidth: true
bottomLeftRadius: Tokens.rounding.largeIncreased
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
UserDock {
greeter: root.greeter
}
}
}
@@ -32,16 +49,21 @@ SnapLayout {
screenHeight: root.screenHeight
}
CustomRect {
Layout.fillHeight: true
ColumnLayout {
Layout.fillWidth: true
bottomRightRadius: Tokens.rounding.largeIncreased
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
topRightRadius: Tokens.rounding.largeIncreased
spacing: Tokens.spacing.medium
SessionDock {
greeter: root.greeter
CustomRect {
Layout.fillHeight: true
Layout.fillWidth: true
bottomRightRadius: Tokens.rounding.largeIncreased
color: Colors.tPalette.m3surfaceContainer
radius: Tokens.rounding.small
topRightRadius: Tokens.rounding.largeIncreased
SessionDock {
greeter: root.greeter
}
}
}
}
+2 -1
View File
@@ -134,7 +134,8 @@ Scope {
id: lockIcon
anchors.centerIn: parent
fontStyle: Tokens.font.icon.builders.extraLarge.size(Tokens.font.icon.extraLarge.pointSize * 3).build()
font.bold: true
font.pointSize: Tokens.font.size.extraLarge * 4
text: "lock"
}
+15 -9
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
@@ -40,7 +39,8 @@ Item {
anchors.centerIn: parent
animate: true
color: root.greeter.launching ? Colors.palette.m3secondary : Colors.palette.m3outline
font: Tokens.font.mono.medium
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.normal
opacity: root.buffer ? 0 : 1
text: {
if (root.greeter.launching)
@@ -51,7 +51,8 @@ Item {
}
Behavior on opacity {
Anim {}
Anim {
}
}
}
@@ -63,13 +64,15 @@ Item {
anchors.verticalCenter: parent.verticalCenter
color: Colors.palette.m3onSurface
elide: Text.ElideLeft
font: Tokens.font.mono.medium
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.normal
horizontalAlignment: Qt.AlignHCenter
opacity: root.greeter.echoResponse && root.buffer ? 1 : 0
text: root.buffer
Behavior on opacity {
Anim {}
Anim {
}
}
}
@@ -86,7 +89,7 @@ Item {
anchors.centerIn: parent
anchors.horizontalCenterOffset: implicitWidth > root.width ? -(implicitWidth - root.width) / 2 : 0
implicitHeight: Tokens.font.body.medium
implicitHeight: Tokens.font.size.normal
implicitWidth: fullWidth
interactive: false
opacity: root.greeter.echoResponse ? 0 : 1
@@ -104,7 +107,8 @@ Item {
scale: 0
Behavior on opacity {
Anim {}
Anim {
}
}
Behavior on scale {
Anim {
@@ -152,13 +156,15 @@ Item {
Behavior on implicitWidth {
id: imWidthBehavior
Anim {}
Anim {
}
}
model: ScriptModel {
values: root.buffer.split("")
}
Behavior on opacity {
Anim {}
Anim {
}
}
}
}
+21 -21
View File
@@ -3,32 +3,32 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Services
SnapLayout {
ColumnLayout {
id: root
required property var greeter
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.large
orientation: Qt.Vertical
spacing: Tokens.spacing.small
CustomText {
Layout.fillWidth: true
color: Colors.palette.m3outline
elide: Text.ElideRight
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
font.family: Config.appearance.font.family.mono
font.weight: 500
text: root.greeter.sessions.length > 0 ? qsTr("%1 session%2").arg(root.greeter.sessions.length).arg(root.greeter.sessions.length === 1 ? "" : "s") : qsTr("Sessions")
}
Item {
CustomClippingRect {
Layout.fillHeight: true
Layout.fillWidth: true
color: "transparent"
radius: Tokens.rounding.small
Loader {
active: opacity > 0
@@ -40,21 +40,22 @@ SnapLayout {
duration: Tokens.anim.durations.extraLarge
}
}
sourceComponent: SnapLayout {
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.largeIncreased
orientation: Qt.Vertical
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3outlineVariant
fontStyle: Tokens.font.icon.large
font.pointSize: Tokens.font.size.extraLarge * 2
text: "desktop_windows"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3outlineVariant
font: Tokens.font.headline.builders.small.width(90).build()
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.large
font.weight: 500
text: qsTr("No Sessions Found")
}
}
@@ -67,7 +68,6 @@ SnapLayout {
clip: true
currentIndex: root.greeter.sessionIndex
highlightFollowsCurrentItem: false
boundsBehavior: ListView.StopAtBounds
model: root.greeter.sessions
spacing: Tokens.spacing.small
@@ -80,7 +80,7 @@ SnapLayout {
anchors.left: parent?.left
anchors.right: parent?.right
implicitHeight: row.implicitHeight + Tokens.padding.small * 2
radius: Tokens.rounding.large
radius: Tokens.rounding.medium - Tokens.padding.small
StateLayer {
onClicked: {
@@ -88,7 +88,7 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: row
anchors.fill: parent
@@ -97,21 +97,20 @@ SnapLayout {
MaterialIcon {
color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant
fontStyle: Tokens.font.icon.extraLarge
font.pointSize: Tokens.font.size.extraLarge
text: modelData.kind === "x11" ? "tv" : "desktop_windows"
}
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.small / 2
orientation: Qt.Vertical
CustomText {
Layout.fillWidth: true
color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
elide: Text.ElideRight
font: Tokens.font.body.builders.medium.weight(Font.Bold).build()
font.pointSize: Tokens.font.size.normal
font.weight: 600
text: modelData.name
}
@@ -119,7 +118,8 @@ SnapLayout {
Layout.fillWidth: true
color: session.index === sessions.currentIndex ? Colors.palette.m3onPrimaryFixedVariant : Colors.palette.m3onSurfaceVariant
elide: Text.ElideRight
font: Tokens.font.mono.small
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
text: modelData.kind
}
}
@@ -129,7 +129,7 @@ SnapLayout {
color: Colors.palette.m3primary
implicitHeight: sessions.currentItem?.implicitHeight ?? 0
implicitWidth: sessions.width
radius: Tokens.rounding.large
radius: Tokens.rounding.medium - Tokens.padding.small
y: sessions.currentItem?.y ?? 0
Behavior on y {
+20 -21
View File
@@ -3,33 +3,33 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import qs.Services
SnapLayout {
ColumnLayout {
id: root
required property var greeter
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.large
orientation: Qt.Vertical
spacing: Tokens.spacing.small
CustomText {
Layout.fillWidth: true
color: Colors.palette.m3outline
elide: Text.ElideRight
font: Tokens.font.mono.builders.small.weight(Font.Medium).build()
font.family: Config.appearance.font.family.mono
font.weight: 500
text: root.greeter.users.length > 0 ? qsTr("%1 user%2").arg(root.greeter.users.length).arg(root.greeter.users.length === 1 ? "" : "s") : qsTr("Users")
}
Item {
CustomClippingRect {
Layout.fillHeight: true
Layout.fillWidth: true
color: "transparent"
radius: Tokens.rounding.small
Loader {
active: opacity > 0
@@ -41,22 +41,23 @@ SnapLayout {
duration: Tokens.anim.durations.extraLarge
}
}
sourceComponent: SnapLayout {
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.largeIncreased
orientation: Qt.Vertical
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3outlineVariant
fill: 1
fontStyle: Tokens.font.icon.large
font.pointSize: Tokens.font.size.extraLarge * 2
text: "account_circle"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3outlineVariant
font: Tokens.font.headline.builders.small.width(90).build()
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.large
font.weight: 500
text: qsTr("No Users Found")
}
}
@@ -69,7 +70,6 @@ SnapLayout {
clip: true
currentIndex: root.greeter.selectedUser ? root.greeter.users.indexOf(root.greeter.selectedUser) : -1
highlightFollowsCurrentItem: false
boundsBehavior: ListView.StopAtBounds
model: root.greeter.users
spacing: Tokens.spacing.small
@@ -82,7 +82,7 @@ SnapLayout {
anchors.left: parent?.left
anchors.right: parent?.right
implicitHeight: row.implicitHeight + Tokens.padding.small * 2
radius: Tokens.rounding.large
radius: Tokens.rounding.medium - Tokens.padding.small
StateLayer {
onClicked: {
@@ -90,14 +90,14 @@ SnapLayout {
}
}
SnapLayout {
RowLayout {
id: row
anchors.fill: parent
anchors.margins: Tokens.padding.small
spacing: Tokens.spacing.medium
ClipRect {
CustomClippingRect {
Layout.preferredHeight: 50
Layout.preferredWidth: 50
radius: Tokens.rounding.full
@@ -106,7 +106,7 @@ SnapLayout {
anchors.centerIn: parent
color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurfaceVariant
fill: 1
fontStyle: Tokens.font.icon.extraLarge
font.pointSize: Tokens.font.size.extraLarge
text: modelData.kind === "x11" ? "tv" : "account_circle"
}
@@ -116,17 +116,16 @@ SnapLayout {
}
}
SnapLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.small / 2
orientation: Qt.Vertical
CustomText {
Layout.fillWidth: true
color: user.index === users.currentIndex ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
elide: Text.ElideRight
font: Tokens.font.body.builders.medium.weight(Font.Bold).build()
font.pointSize: Tokens.font.size.normal
font.weight: 600
text: modelData.username
}
}
@@ -136,7 +135,7 @@ SnapLayout {
color: Colors.palette.m3primary
implicitHeight: users.currentItem?.implicitHeight ?? 0
implicitWidth: users.width
radius: Tokens.rounding.large
radius: Tokens.rounding.medium - Tokens.padding.small
y: users.currentItem?.y ?? 0
Behavior on y {
+171
View File
@@ -0,0 +1,171 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Components
import qs.Helpers
import qs.Services
ColumnLayout {
id: root
required property int rootHeight
anchors.left: parent.left
anchors.margins: Tokens.padding.large * 2
anchors.right: parent.right
spacing: Tokens.spacing.small
Loader {
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: -Tokens.padding.large
Layout.topMargin: Tokens.padding.large * 2
active: root.rootHeight > 610
visible: active
sourceComponent: CustomText {
color: Colors.palette.m3primary
font.pointSize: Tokens.font.size.extraLarge
font.weight: 500
text: qsTr("Weather")
}
}
RowLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.largeIncreased
MaterialIcon {
animate: true
color: Colors.palette.m3secondary
font.pointSize: Tokens.font.size.extraLarge * 2.5
text: Weather.icon
}
ColumnLayout {
spacing: Tokens.spacing.small
CustomText {
Layout.fillWidth: true
animate: true
color: Colors.palette.m3secondary
elide: Text.ElideRight
font.pointSize: Tokens.font.size.large
font.weight: 500
text: Weather.description
}
CustomText {
Layout.fillWidth: true
animate: true
color: Colors.palette.m3onSurfaceVariant
elide: Text.ElideRight
font.pointSize: Tokens.font.size.normal
text: qsTr("Humidity: %1%").arg(Weather.humidity)
}
}
Loader {
Layout.rightMargin: Tokens.padding.small
active: root.width > 400
visible: active
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.small
CustomText {
Layout.fillWidth: true
animate: true
color: Colors.palette.m3primary
elide: Text.ElideLeft
font.pointSize: Tokens.font.size.extraLarge
font.weight: 500
horizontalAlignment: Text.AlignRight
text: Weather.temp
}
CustomText {
Layout.fillWidth: true
animate: true
color: Colors.palette.m3outline
elide: Text.ElideLeft
font.pointSize: Tokens.font.size.smaller
horizontalAlignment: Text.AlignRight
text: qsTr("Feels like: %1").arg(Weather.feelsLike)
}
}
}
}
Loader {
id: forecastLoader
Layout.bottomMargin: Tokens.padding.large * 2
Layout.fillWidth: true
Layout.topMargin: Tokens.spacing.small
active: root.rootHeight > 820
visible: active
sourceComponent: RowLayout {
spacing: Tokens.spacing.largeIncreased
Repeater {
model: {
const forecast = Weather.hourlyForecast;
const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5;
if (!forecast)
return Array.from({
length: count
}, () => null);
const start = Math.max(0, Weather.currentHourIndex);
return forecast.slice(start, start + count);
}
ColumnLayout {
id: forecastHour
required property var modelData
Layout.fillWidth: true
spacing: Tokens.spacing.small
CustomText {
Layout.fillWidth: true
color: Colors.palette.m3outline
font.pointSize: Tokens.font.size.larger
horizontalAlignment: Text.AlignHCenter
text: {
const hour = forecastHour.modelData?.hour ?? 0;
return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`;
}
}
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
font.pointSize: Tokens.font.size.extraLarge * 1.5
font.weight: 500
text: forecastHour.modelData?.icon ?? "cloud_alert"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3secondary
font.pointSize: Tokens.font.size.larger
text: Config.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C`
}
}
}
}
}
Timer {
interval: 900000 // 15 minutes
repeat: true
running: true
triggeredOnStart: true
onTriggered: Weather.reload()
}
}
-10
View File
@@ -77,16 +77,6 @@ Singleton {
"99": "thunderstorm"
})
function getAppCategoryIcon(name: string, fallback: string): string {
const categories = DesktopEntries.heuristicLookup(name)?.categories;
if (categories)
for (const [key, value] of Object.entries(categoryIcons))
if (categories.includes(key))
return value;
return fallback;
}
function getAppIcon(name: string, fallback: string): string {
const icon = DesktopEntries.heuristicLookup(name)?.icon;
if (fallback !== "undefined")
+122
View File
@@ -0,0 +1,122 @@
pragma Singleton
import Quickshell
import Quickshell.Networking
import QtQuick
Singleton {
id: root
property bool active: false
readonly property list<Network> connectedNetworks: networks.filter(n => n.connected)
property Network connectingNetwork
readonly property list<NetworkDevice> devices: Networking.devices.values
property Network failedNetwork
readonly property list<Network> knownNetworks: networks.filter(n => n.known && !n.connected)
readonly property list<Network> networks: {
const list = [];
for (const d of wifiDevices) {
for (const n of d.networks.values) {
if (!list.includes(n))
list.push(n);
}
}
return list;
}
property bool scanning: false
readonly property list<Network> unknownNetworks: networks.filter(n => !n.known)
readonly property list<WifiDevice> wifiDevices: devices.filter(d => wifiDevice(d))
readonly property bool wifiEnabled: Networking.wifiEnabled
signal networkConnected
function forgetNetwork(target): void {
if (!target) {
return;
}
target.forget();
}
function isSecure(security): bool {
return (security === WifiSecurityType.WpaPsk || security === WifiSecurityType.Wpa2Psk || security === WifiSecurityType.Sae);
}
function requestConnect(network: Network, secret = undefined): void {
connectingNetwork = network;
if (secret === undefined || secret === "") {
network.connect();
} else {
(network as WifiNetwork).connectWithPsk(secret);
}
}
function setScan(value: bool): void {
for (const d of wifiDevices) {
d.scannerEnabled = value;
}
}
function setWifi(value: bool): void {
Networking.wifiEnabled = value;
}
function wifiDevice(dev): bool {
return dev.type === DeviceType.Wifi;
}
onActiveChanged: {
for (const d of wifiDevices)
d.scannerEnabled = active;
}
Timer {
id: flushFailed
interval: 5000
running: root.failedNetwork
onTriggered: {
root.failedNetwork = null;
}
}
Timer {
id: checkConnection
interval: 500
repeat: true
running: root.connectingNetwork
onTriggered: {
var completedNetwork;
switch (root.connectingNetwork.state) {
case ConnectionState.Connecting:
break;
case ConnectionState.Connected:
completedNetwork = root.connectingNetwork;
root.networkConnected();
break;
case ConnectionState.Disconnected:
root.failedNetwork = root.connectingNetwork;
completedNetwork = root.connectingNetwork;
break;
}
if (completedNetwork) {
root.connectingNetwork = null;
}
}
}
Timer {
interval: 10000
running: checkConnection.running
onTriggered: {
root.failedNetwork = root.connectingNetwork;
root.connectingNetwork = null;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
import QtQuick
import ZShell.Config
import qs.Services
import qs.Modules.Settings.Common
import qs.Modules.Bar.Popouts.Network
import qs.Components
import qs.Helpers
CustomText {
required property var modelData
bottomPadding: Tokens.spacing.extraSmall
color: Colors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.smaller
text: {
if (modelData.type === "known") {
const count = Network.knownNetworks.filter(n => !n.connected).length;
return qsTr("%1 known network%2").arg(count).arg(count === 1 ? "" : "s");
}
if (modelData.type === "unknown") {
const count = Network.unknownNetworks.filter(n => !n.connected).length;
return qsTr("%1 network%2 available").arg(count).arg(count === 1 ? "" : "s");
}
return qsTr("object unknown");
}
topPadding: Tokens.spacing.small
}
+118
View File
@@ -0,0 +1,118 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Modules.Settings.Common
import qs.Modules.Bar.Popouts.Network
import qs.Components
import qs.Helpers
import qs.Helpers.Network
import qs.Services
ConnectedRect {
id: networkItem
readonly property int connectedCount: Network.connectedNetworks.length
readonly property bool connecting: Network.connectingNetwork === modelData
property int horizontalPadding: Tokens.padding.largeIncreased
readonly property bool inConnectedGroup: index < connectedCount
// sectioning first / last item in list reminder
// if index === network.connectedNetworks.length - 1
// if index === network.connectedNetworks.length - 1 + network.knownNetworks.length - 2
// if index === network.connectedNetworks.length - 1 + network.knownNetworks.length
// list.model.values.length - 1
required property int index
readonly property bool isSecure: Network.isSecure(modelData.security)
required property ListView list
required property var modelData
property int verticalPadding: Tokens.padding.smaller
Layout.fillWidth: true
first: !inConnectedGroup && index === connectedCount + 1
implicitHeight: rowLayout.implicitHeight + verticalPadding * 2
last: inConnectedGroup ? index === connectedCount - 1 : index === (list?.count ?? -1)
radius: Tokens.rounding.small
RowLayout {
id: rowLayout
Layout.preferredHeight: visible ? rowLayout.implicitHeight + Tokens.padding.smaller * 2 : 0
anchors.fill: parent
anchors.leftMargin: networkItem.horizontalPadding
anchors.rightMargin: networkItem.horizontalPadding
Column {
id: column
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
Layout.leftMargin: Tokens.spacing.extraSmall
Layout.rightMargin: Tokens.spacing.extraSmall
color: networkItem.modelData.active ? Colors.palette.m3primary : Colors.palette.m3onSurface
elide: Text.ElideRight
text: networkItem.modelData.name ? networkItem.modelData.name : qsTr("Unknown Network")
}
CustomText {
id: subtext
anchors.left: parent.left
anchors.right: parent.right
color: Colors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Tokens.font.size.small
text: networkItem.modelData.connected ? qsTr("Connected: %1 strength").arg(Math.round(networkItem.modelData.signalStrength * 100) + "%") : qsTr("%1 strength").arg(Math.round(networkItem.modelData.signalStrength * 100) + "%")
}
}
Item {
Layout.alignment: Qt.AlignRight
implicitHeight: icon.height
implicitWidth: icon.width
MaterialIcon {
id: icon
color: networkItem.modelData.active ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.large
opacity: networkItem.connecting ? 0 : 1
text: Icons.getNetworkIcon(networkItem.modelData.signalStrength * 100, networkItem.isSecure)
Behavior on opacity {
Anim {
}
}
}
Loader {
active: opacity > 0
anchors.fill: parent
opacity: networkItem.connecting ? 1 : 0
Behavior on opacity {
Anim {
}
}
sourceComponent: CircularIndicator {
bgColor: "transparent"
running: true
}
}
}
}
StateLayer {
color: networkItem.modelData.active ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
onClicked: {
if (networkItem.isSecure && !networkItem.known) {
PopupManager.requestOpen(Qt.resolvedUrl("../../Modules/Bar/Popouts/Network/PSKOverlay.qml"), {
network: networkItem.modelData
});
} else {
Network.requestConnect(networkItem.modelData);
}
}
}
}
+74
View File
@@ -0,0 +1,74 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Services
import qs.Components
import qs.Modules.Settings.Common
CustomSwitch {
id: toggleItem
readonly property alias bg: bg
property alias first: bg.first
property alias last: bg.last
property string subtext
Layout.fillWidth: true
cLayer: 2
horizontalPadding: Tokens.padding.largeIncreased
implicitHeight: Math.max(implicitContentHeight, implicitIndicatorHeight) + verticalPadding * 2
implicitWidth: implicitContentWidth + implicitIndicatorWidth + horizontalPadding * 2
indicator.anchors.right: right
indicator.anchors.rightMargin: toggleItem.horizontalPadding
indicator.anchors.verticalCenter: verticalCenter
verticalPadding: Tokens.padding.normal
background: ConnectedRect {
id: bg
StateLayer {
id: stateLayer
manualPressOverride: toggleItem.pressed
}
}
contentItem: Item {
anchors.left: parent.left
anchors.leftMargin: toggleItem.horizontalPadding
anchors.right: toggleItem.indicator.left
anchors.rightMargin: Tokens.spacing.normal
implicitHeight: column.implicitHeight
implicitWidth: column.implicitWidth
ColumnLayout {
id: column
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 0
CustomText {
id: label
Layout.fillWidth: true
elide: Text.ElideRight
font.pointSize: Tokens.font.size.smaller
text: toggleItem.text
}
CustomText {
id: subtext
Layout.fillWidth: true
color: Colors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Tokens.font.size.small
text: toggleItem.subtext
visible: toggleItem.subtext
}
}
}
onPressed: stateLayer.press(stateLayer.mouseX, stateLayer.mouseY)
}
+1 -1
View File
@@ -53,7 +53,7 @@ CustomRect {
radius: Tokens.rounding.full
width: row.implicitWidth + Tokens.padding.small * 2
SnapLayout {
RowLayout {
id: row
anchors.centerIn: parent
+43 -105
View File
@@ -5,7 +5,7 @@ import Quickshell
import Quickshell.Io
import QtQuick
import ZShell.Models
import ZShell.Wallpaper
import ZShell.Internal
import ZShell.Config
import qs.Components
import qs.Services
@@ -16,48 +16,24 @@ Searcher {
id: root
property string actualCurrent: WallpaperPath.currentWallpaperPath
property alias crops: adapter.monitorCrops
readonly property string current: showPreview ? previewPath : actualCurrent
readonly property string currentThumbnail: thumbnailFor(current)
readonly property bool currentIsVideo: isVideoPath(current)
property alias monitorCrops: monitorCrops
property bool pendingPreviewClear
property bool previewColorLock
property string previewPath
property bool recentlyChanged
property bool showPreview: false
property int cropVersion: 0
function getCategoryFor(w: WallpaperEntry): string {
function getCategoryFor(w: FileSystemEntry): string {
let category = w.parentDir.slice(Paths.wallsdir.length + 1);
if (category.includes("/"))
category = category.slice(0, category.indexOf("/"));
return category;
}
readonly property var videoExts: ["mp4", "mkv", "webm", "avi", "mov", "wmv", "flv", "m4v", "mpg", "mpeg", "3gp", "ogv", "ts", "vob"]
function isVideoPath(path: string): bool {
if (!path)
return false;
const dot = path.lastIndexOf(".");
if (dot < 0)
return false;
return videoExts.includes(path.slice(dot + 1).toLowerCase());
}
function thumbnailFor(path: string): string {
if (!path)
return "";
for (const entry of root.list) {
if (entry.path === path)
return entry.thumbnailPath || path;
}
return path;
}
function getCrop(screen: string): var {
return wallpapers.crop(root.current, screen);
return root.crops[screen];
}
function preview(path: string): void {
@@ -74,18 +50,19 @@ Searcher {
else if (zoom > 5.0)
zoom = 5.0;
wallpapers.setCrop(root.current, screen, {
root.crops[screen] = {
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
zoom: zoom
});
};
}
function setWallpaper(path: string): void {
actualCurrent = path;
WallpaperPath.currentWallpaperPath = path;
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0));
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
if (Config.colors.schemeGen)
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.colors.mode}`]);
@@ -119,13 +96,38 @@ Searcher {
target: "wallpaper"
}
WallpaperDb {
FileView {
id: monitorCrops
path: `${Paths.state}/wallpaper-crops.json`
watchChanges: true
onAdapterUpdated: cropWriteDelay.restart()
onFileChanged: reload()
JsonAdapter {
id: adapter
property var monitorCrops: ({})
}
}
Timer {
id: cropWriteDelay
interval: 100
repeat: false
running: false
onTriggered: monitorCrops.writeAdapter()
}
FileSystemModel {
id: wallpapers
dbPath: `${Paths.state}/wallpapers.sqlite`
cacheSize: wallpaper.largestBufferSize
requireHardwareCodec: true
filter: FileSystemModel.Images
path: Config.general.wallpaperPath
recursive: true
}
Process {
@@ -144,100 +146,36 @@ Searcher {
WallpaperService {
id: wallpaper
dbPath: wallpapers.dbPath
path: root.current
}
Connections {
target: wallpapers
function onCacheStored(path: string): void {
if (path === root.current)
wallpaper.invalidateCache();
}
function onCropsChanged(path: string): void {
if (path === root.current)
root.cropVersion++;
}
}
Variants {
id: screenVariants
model: Quickshell.screens
WallpaperObject {
id: obj
readonly property var crops: root.getCrop(modelData.name)
required property var modelData
// Crop animation only for edits, never for wallpaper swaps.
property bool animateCrop: false
cropHeight: crops?.height ?? 1.0
cropWidth: crops?.width ?? 1.0
cropX: crops?.x ?? 0.0
cropY: crops?.y ?? 0.0
screen: modelData.name
service: wallpaper
// Apply the wallpaper's own crop. Driven off the service's pathChanged
// (which fires after applyPath has snapshotted the outgoing frame with
// the outgoing crop) and off crop edits, never as a reactive binding on
// the wallpaper path — so a swap applies the incoming crop atomically
// after the base is captured.
function seedCrop(): void {
// Load the current wallpaper's crop without pushing: the service
// already read it from the database. This only seeds the values so
// a later edit animates from the right starting point.
obj.syncCrop(root.getCrop(modelData.name));
}
// Apply an edited crop: assign via the setters so the Behaviors animate
// the numbers and push each intermediate value to the service.
function editCrop(): void {
const c = root.getCrop(modelData.name);
obj.cropX = c?.x ?? 0.0;
obj.cropY = c?.y ?? 0.0;
obj.cropWidth = c?.width ?? 1.0;
obj.cropHeight = c?.height ?? 1.0;
obj.zoom = c?.zoom ?? 1.0;
}
Component.onCompleted: seedCrop()
onScreenChanged: seedCrop()
zoom: crops?.zoom ?? 1.0
Behavior on cropHeight {
enabled: obj.animateCrop
Anim {}
}
Behavior on cropWidth {
enabled: obj.animateCrop
Anim {}
}
Behavior on cropX {
enabled: obj.animateCrop
Anim {}
}
Behavior on cropY {
enabled: obj.animateCrop
Anim {}
}
}
}
Connections {
target: wallpaper
function onPathChanged(): void {
for (const obj of screenVariants.instances) {
obj.animateCrop = false;
obj.seedCrop();
}
}
}
Connections {
target: root
function onCropVersionChanged(): void {
for (const obj of screenVariants.instances) {
obj.animateCrop = true;
obj.editCrop();
}
}
}
}
+8 -66
View File
@@ -4,13 +4,11 @@ import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Modules.Bar.Components
import qs.Modules.Bar.Popouts
import ZShell
SnapLayout {
GridLayout {
id: root
required property bool fullscreen
@@ -24,7 +22,7 @@ SnapLayout {
function axisCenterOf(item: Item): real {
const c = item.mapToItem(root, item.implicitWidth / 2, item.implicitHeight / 2);
return horizontal ? ZUtils.snap(c.x, item) : ZUtils.snap(c.y, item);
return horizontal ? Math.floor(c.x) : Math.floor(c.y);
}
function checkPopout(pos: real): void {
@@ -76,47 +74,9 @@ SnapLayout {
return ch?.entryId ?? "";
}
readonly property var sectionRects: {
const count = repeater.count; // dependency: re-run when items are added/removed
const names = ["start", "middle", "end"]; // constant ids by position
const bounds = [null];
let spacers = 0;
for (let i = 0; i < count; i++) {
const it = repeater.itemAt(i) as EntryWrapper;
if (!it)
continue;
if (it.entryId === "spacer") {
bounds.push(null);
spacers++;
continue;
}
const l = it.x, t = it.y, r = it.x + it.width, b = it.y + it.height;
const cur = bounds[spacers];
bounds[spacers] = cur ? {
l: Math.min(cur.l, l),
t: Math.min(cur.t, t),
r: Math.max(cur.r, r),
b: Math.max(cur.b, b)
} : {
l,
t,
r,
b
};
}
return bounds.map((c, n) => ({
id: names[n] ?? `section${n}`,
rect: c ? Qt.rect(c.l, c.t, c.r - c.l, c.b - c.t) : Qt.rect(0, 0, 0, 0)
}));
}
spacing: Tokens.spacing.small
orientation: horizontal ? Qt.Horizontal : Qt.Vertical
columnSpacing: Tokens.spacing.small
columns: horizontal ? -1 : 1
rowSpacing: Tokens.spacing.small
Repeater {
id: repeater
@@ -246,14 +206,6 @@ SnapLayout {
}
}
DelegateChoice {
roleValue: "network"
delegate: EntryWrapper {
NetworkWidget {}
}
}
DelegateChoice {
roleValue: "media"
@@ -268,26 +220,16 @@ SnapLayout {
}
component EntryWrapper: Item {
readonly property int section: {
let n = 0;
for (let i = 0; i < index; i++) {
if (repeater.model.values[i].id === "spacer")
n++;
}
return n;
}
readonly property string entryId: modelData.id
required property int index
required property var modelData
default property Item item
required property var modelData
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
Layout.bottomMargin: !root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0
Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.rowSpacing + Tokens.spacing.extraSmall : 0
Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0
Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.columnSpacing + Tokens.spacing.extraSmall : 0
children: item
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
-1
View File
@@ -9,7 +9,6 @@ import qs.Components
Item {
id: root
readonly property var sections: (content.item as Bar)?.sectionRects ?? []
readonly property int clampedExtent: Math.max(Config.bar.border, extent)
readonly property int contentThickness: Math.floor(Math.max(Config.bar.height, Tokens.sizes.bar.innerSize * (horizontal ? 1 : 1.5))) + padding * 2
readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness
+49
View File
@@ -0,0 +1,49 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Effects
import ZShell.Config
import qs.Components
import qs.Services
Item {
id: root
required property Item bar
required property ScreenState screenState
anchors.fill: parent
CustomRect {
anchors.fill: parent
anchors.margins: -1
color: Colors.palette.m3surface
layer.enabled: true
layer.effect: MultiEffect {
maskEnabled: true
maskInverted: true
maskSource: mask
maskSpreadAtMin: 1
maskThresholdMin: 0.5
}
}
Item {
id: mask
anchors.fill: parent
layer.enabled: true
visible: false
Rectangle {
anchors.fill: parent
anchors.margins: Config.bar.border + 1
anchors.topMargin: root.bar.implicitHeight + 1
radius: Config.bar.border > 0 ? Config.bar.rounding : 0
topLeftRadius: Config.bar.rounding
topRightRadius: Config.bar.rounding
}
}
}
+3 -7
View File
@@ -4,7 +4,6 @@ import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Modules.Bar.Popouts
import qs.Modules.Bar.Components.Common
import qs.Helpers
@@ -44,11 +43,9 @@ WidgetBase {
timeTokens: timeTokens
};
}
required property SnapLayout loader
required property GridLayout loader
required property Wrapper popouts
readonly property int roundedWidth: Math.round(timeText.implicitWidth)
readonly property int evenWidth: roundedWidth % 2 === 0 ? roundedWidth : roundedWidth + 1
readonly property real size: horizontal ? evenWidth + Tokens.padding.medium * 2 : verticalColumn.implicitHeight + Tokens.padding.medium * 2
readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.medium * 2 : verticalColumn.implicitHeight + Tokens.padding.medium * 2
required property ScreenState screenState
implicitHeight: horizontal ? baseSize : size
@@ -70,8 +67,7 @@ WidgetBase {
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: verticalColumn
anchors.centerIn: parent
@@ -24,7 +24,7 @@ Row {
color: Battery.getColors(root.percentage, root.devState).bg
height: root.batHeight
radius: root.radius
width: root.batWidth - 1
width: root.batWidth
CustomText {
color: Battery.getColors(root.percentage, root.devState).fg
+1 -2
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Modules.Bar.Components.Common
@@ -14,7 +13,7 @@ WidgetBase {
readonly property int textWidth: Math.min(metrics.width, 200)
implicitHeight: horizontal ? baseSize : layout.implicitHeight + Tokens.padding.small * 2
implicitWidth: horizontal ? (layout.implicitWidth % 2 === 0 ? layout.implicitWidth : layout.implicitWidth + 1) + Tokens.padding.small * 2 : baseSize
implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.small * 2 : baseSize
radius: Tokens.rounding.full
Behavior on implicitHeight {
+1 -2
View File
@@ -1,7 +1,6 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import qs.Modules
@@ -12,7 +11,7 @@ Item {
anchors.top: parent.top
implicitWidth: layout.implicitWidth
SnapLayout {
RowLayout {
id: layout
anchors.bottom: parent.bottom
+12 -9
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import qs.Components
import ZShell.Config
@@ -13,6 +12,7 @@ GridLayout {
property real animatedPercentage: 0
readonly property real arcStartAngle: 0.75 * Math.PI
readonly property real arcSweep: 1.5 * Math.PI
readonly property real dpr: (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1
required property bool horizontal
property string icon
required property color iconColor
@@ -23,12 +23,17 @@ GridLayout {
property bool warning: percentage * 100 >= warningThreshold
property int warningThreshold: 80
function snap(v) {
return Math.round(v * dpr) / dpr;
}
columnSpacing: Tokens.spacing.medium
columns: horizontal ? -1 : 1
percentage: 0
Behavior on animatedPercentage {
Anim {}
Anim {
}
}
Component.onCompleted: animatedPercentage = percentage
@@ -54,7 +59,7 @@ GridLayout {
Layout.preferredHeight: root.horizontal ? icon.implicitHeight - Tokens.padding.extraSmall : 4
Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
radius: Tokens.rounding.full
radius: Math.min(width, height) / 2
Item {
id: clipper
@@ -64,20 +69,18 @@ GridLayout {
anchors.left: root.horizontal ? undefined : parent.left
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
clip: true
implicitHeight: root.horizontal ? root.percentage * track.height : track.height * 2
implicitWidth: root.horizontal ? track.width * 2 : root.percentage * track.width
height: root.horizontal ? root.snap(root.percentage * track.height) : track.height * 2
width: root.horizontal ? track.width * 2 : root.snap(root.percentage * track.width)
CustomRect {
anchors.bottom: root.horizontal ? parent.bottom : undefined
anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined
anchors.left: root.horizontal ? undefined : parent.left
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
color: root.mainColor
height: track.height
radius: track.radius
implicitHeight: track.height
implicitWidth: track.width
width: track.width
}
}
}
-3
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell.Services
import qs.Services
@@ -34,7 +33,6 @@ WidgetBase {
anchors.horizontalCenterOffset: root.horizontal ? 0 : 1
anchors.verticalCenterOffset: root.horizontal ? 0 : -3
columnSpacing: Tokens.spacing.small
rowSpacing: 0
columns: root.horizontal ? -1 : 1
ServiceRef {
@@ -53,7 +51,6 @@ WidgetBase {
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: root.horizontal
Layout.fillWidth: !root.horizontal
horizontal: root.horizontal
icon: "memory"
iconColor: root.screenState.resources ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
+33 -10
View File
@@ -4,7 +4,6 @@ import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Helpers
import qs.Modules.Bar.Components.StatusIcons
import qs.Modules.Bar.Components.Common
@@ -32,7 +31,7 @@ WidgetBase {
return -1;
}
readonly property real size: horizontal ? grid.implicitWidth + grid.anchors.leftMargin + grid.anchors.rightMargin : grid.implicitHeight + grid.anchors.bottomMargin + grid.anchors.topMargin
readonly property int spacing: Tokens.spacing.extraSmall
readonly property int spacing: Tokens.spacing.medium / 2
// Entries that can shrink to nothing, spacing included
function collapsed(entry: var): bool {
@@ -52,15 +51,17 @@ WidgetBase {
Behavior on implicitHeight {
enabled: !root.horizontal
Anim {}
Anim {
}
}
Behavior on implicitWidth {
enabled: root.horizontal
Anim {}
Anim {
}
}
SnapLayout {
GridLayout {
id: grid
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.medium
@@ -68,8 +69,7 @@ WidgetBase {
anchors.leftMargin: root.horizontal ? Tokens.padding.extraSmall : 0
anchors.rightMargin: root.horizontal ? Tokens.padding.extraSmall : 0
anchors.topMargin: root.horizontal ? 0 : Tokens.padding.extraSmall
orientation: root.horizontal ? Qt.Horizontal : Qt.Vertical
spacing: root.horizontal ? Tokens.spacing.extraSmall : -2
columns: root.horizontal ? -1 : 1
Repeater {
model: ScriptModel {
@@ -105,13 +105,36 @@ WidgetBase {
}
}
DelegateChoice {
roleValue: "bluetooth"
delegate: EntryWrapper {
name: "bluetooth"
BluetoothWidget {
}
}
}
DelegateChoice {
roleValue: "network"
delegate: EntryWrapper {
name: "network"
NetworkWidget {
}
}
}
DelegateChoice {
roleValue: "power"
delegate: EntryWrapper {
name: "upower"
UPowerWidget {}
UPowerWidget {
}
}
}
}
@@ -134,8 +157,8 @@ WidgetBase {
Layout.rightMargin: root.horizontal ? Math.round(rightGap) : 0
Layout.topMargin: root.horizontal ? 0 : Math.round(leftGap)
children: item
implicitHeight: item?.height ?? item?.implicitHeight ?? 0
implicitWidth: item?.width ?? item?.implicitWidth ?? 0
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
Behavior on leftGap {
Anim {
@@ -1,13 +1,12 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Daemons
import qs.Components
import qs.Services
MaterialIcon {
id: root
id: speaker
required property bool horizontal
@@ -16,8 +15,6 @@ MaterialIcon {
fill: 1
fontStyle: Tokens.font.icon.small
text: Audio.muted ? "volume_off" : "volume_up"
width: Math.round(implicitWidth)
height: Math.round(implicitHeight)
Behavior on Layout.maximumWidth {
Anim {}
@@ -0,0 +1,14 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Services
import qs.Components
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
animate: true
color: Colors.palette.m3onSurface // Network.connected ? root.textColor : Colors.palette.m3error
fill: 1
font.pointSize: Tokens.font.size.larger
text: "bluetooth"
}
@@ -1,13 +1,12 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Daemons
import qs.Components
import qs.Services
MaterialIcon {
id: root
id: mic
required property bool horizontal
@@ -16,8 +15,6 @@ MaterialIcon {
fill: 1
fontStyle: Tokens.font.icon.small
text: Audio.sourceMuted ? "mic_off" : "mic"
width: Math.round(implicitWidth)
height: Math.round(implicitHeight)
Behavior on Layout.maximumWidth {
Anim {}
@@ -0,0 +1,14 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import qs.Services
import qs.Components
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
animate: true
color: Colors.palette.m3onSurface // Network.connected ? root.textColor : Colors.palette.m3error
fill: 1
font.pointSize: Tokens.font.size.larger
text: "android_wifi_4_bar"
}
@@ -1,7 +1,6 @@
import Quickshell.Services.UPower
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Modules.Bar.Components.Common
import qs.Components
+3 -7
View File
@@ -2,11 +2,10 @@ import QtQuick.Layouts
import QtQuick
import Quickshell
import Quickshell.Services.SystemTray
import ZShell.Config
import ZShell.Components
import qs.Helpers
import qs.Modules.Bar.Popouts
import qs.Components
import ZShell.Config
import qs.Services
Item {
@@ -16,11 +15,11 @@ Item {
readonly property real dpr: Hypr.monitorFor(loader?.screen).scale
required property int ind
required property SystemTrayItem item
required property SnapLayout loader
required property GridLayout loader
required property Wrapper popouts
function resolveIcon(app: string, icon: string): string {
if (app === "discord_status_icon_1" && Config.bar.tray.replaceIcons) {
if (app === "chrome_status_icon_1") {
return Quickshell.iconPath("discord-tray");
} else if (app === "AyuGramDesktop") {
if (icon === Quickshell.iconPath("com.ayugram.desktop-attention-symbolic"))
@@ -51,8 +50,6 @@ Item {
radius: Tokens.rounding.full
StateLayer {
id: layer
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
color: icon.layer.enabled && root.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
@@ -80,7 +77,6 @@ Item {
anchors.centerIn: parent
antialiasing: true
backer.retainWhileLoading: true
color: root.current && !Config.bar.tray.showOnHover ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
implicitSize: Config.bar.tray.trayIconSize * root.dpr
layer.enabled: Config.bar.tray.recolorIcons
+4 -5
View File
@@ -4,7 +4,6 @@ import QtQuick
import QtQuick.Layouts
import Quickshell.Services.SystemTray
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Modules.Bar.Components.Common
import qs.Modules.Bar.Components.Tray
@@ -16,7 +15,7 @@ WidgetBase {
readonly property alias items: repeater
readonly property alias layout: sysGrid
required property SnapLayout loader
required property GridLayout loader
readonly property int padding: Tokens.padding.extraSmall
required property Wrapper popouts
readonly property real size: horizontal ? sysGrid.implicitWidth + sysGrid.anchors.leftMargin + sysGrid.anchors.rightMargin : sysGrid.implicitHeight + sysGrid.anchors.topMargin + sysGrid.anchors.bottomMargin
@@ -29,7 +28,7 @@ WidgetBase {
radius: Tokens.rounding.full
topRightRadius: horizontal ? Tokens.rounding.small / 2 : Tokens.rounding.full
SnapLayout {
GridLayout {
id: sysGrid
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.extraSmall
@@ -37,8 +36,8 @@ WidgetBase {
anchors.leftMargin: root.horizontal ? Tokens.padding.extraSmall : 0
anchors.rightMargin: root.horizontal ? Tokens.padding.extraSmall : 0
anchors.topMargin: root.horizontal ? 0 : Tokens.padding.extraSmall
orientation: root.horizontal ? Qt.Horizontal : Qt.Vertical
spacing: root.horizontal ? Tokens.spacing.extraSmall : -2
columns: root.horizontal ? -1 : 1
rowSpacing: -2
Repeater {
id: repeater
-1
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Modules.Bar.Components.Common
+1 -1
View File
@@ -17,7 +17,7 @@ Item {
readonly property int maxSize: {
const otherModules = bar.children.filter(c => c.enabled && c.entryId && c.item !== this && c.entryId !== "spacer");
const otherSize = otherModules.reduce((acc, curr) => acc + (horizontal ? (curr.item?.nonAnimWidth ?? curr.width ?? 0) : (curr.item.nonAnimHeight ?? curr.height ?? 0)), 0);
return horizontal ? (bar.width - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 4);
return horizontal ? (bar.width - otherSize - bar.columnSpacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.rowSpacing * (bar.children.length - 1) - bar.vPadding * 4);
}
clip: true
+27 -25
View File
@@ -12,14 +12,13 @@ import qs.Services
Item {
id: root
property real activeWorkspaceMargin: Tokens.padding.extraSmall / 2
readonly property int spacing: Tokens.spacing.extraSmall / 2
property real activeWorkspaceMargin: Math.ceil(Tokens.padding.medium / 4)
readonly property int effectiveActiveWorkspaceId: monitor?.activeWorkspace?.id ?? 1
required property bool horizontal
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
required property ShellScreen screen
readonly property real shortSize: Math.max(Config.bar.height, Tokens.sizes.bar.innerSize)
readonly property real size: (workspaceButtonWidth * workspacesShown) + (spacing * Math.max(0, workspacesShown - 1)) + activeWorkspaceMargin * 2
readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2
property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
readonly property list<var> workspaces: Hyprland.workspaces.values.filter(w => w.monitor === root.monitor)
@@ -60,17 +59,15 @@ Item {
anchors.fill: parent
anchors.margins: root.activeWorkspaceMargin
columnSpacing: root.spacing
columnSpacing: 0
columns: root.horizontal ? root.workspacesShown : 1
rowSpacing: root.spacing
rowSpacing: 0
rows: root.horizontal ? 1 : root.workspacesShown
layer.enabled: true
layer.mipmap: true
Repeater {
model: root.workspaces
CustomRect {
Button {
id: button
required property int index
@@ -78,19 +75,27 @@ Item {
implicitHeight: indicator.indicatorThickness
implicitWidth: indicator.indicatorThickness
radius: Tokens.rounding.full
width: root.workspaceButtonWidth
CustomText {
anchors.centerIn: parent
color: Colors.palette.m3onSecondaryContainer
text: button.modelData?.name ?? ""
background: Item {
id: workspaceButtonBackground
implicitHeight: root.workspaceButtonWidth
implicitWidth: root.workspaceButtonWidth
CustomText {
anchors.centerIn: parent
color: Colors.palette.m3onSecondaryContainer
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
text: button.modelData?.name ?? ""
verticalAlignment: Text.AlignVCenter
}
}
StateLayer {
onPressed: {
const ws = button.modelData.name;
Hyprland.dispatch(Hyprland.usingLua ? `hl.dsp.focus({ workspace= "${ws}"})` : `workspace ${ws}`);
}
onPressed: {
const ws = button.modelData.name;
Hyprland.dispatch(Hyprland.usingLua ? `hl.dsp.focus({ workspace= "${ws}"})` : `workspace ${ws}`);
}
}
}
@@ -99,10 +104,8 @@ Item {
CustomRect {
id: indicator
readonly property real step: root.workspaceButtonWidth + root.spacing
property real indicatorLength: (Math.abs(idxPair.idx1 - idxPair.idx2) + 1) * root.workspaceButtonWidth + Math.abs(idxPair.idx1 - idxPair.idx2) * root.spacing
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * step + root.activeWorkspaceMargin
property real indicatorLength: (Math.abs(idxPair.idx1 - idxPair.idx2) + 1) * root.workspaceButtonWidth
property real indicatorPosition: Math.min(idxPair.idx1, idxPair.idx2) * root.workspaceButtonWidth + root.activeWorkspaceMargin
property real indicatorThickness: root.workspaceButtonWidth
anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
@@ -126,10 +129,9 @@ Item {
implicitHeight: grid.height
implicitWidth: grid.width
source: grid
autoPaddingEnabled: false
sourceColor: Colors.palette.m3onSurface
x: root.horizontal ? -indicator.x + root.activeWorkspaceMargin : 0
y: root.horizontal ? 0 : -indicator.y + root.activeWorkspaceMargin
x: root.horizontal ? -indicator.x + 3 : 0
y: root.horizontal ? 0 : -indicator.y + 3
}
}
}
+38 -47
View File
@@ -5,7 +5,6 @@ import Quickshell.Services.Pipewire
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import QtQuick.Controls
import ZShell.Config
import qs.Components
@@ -34,7 +33,8 @@ Item {
y: parent.y
Behavior on implicitHeight {
Anim {}
Anim {
}
}
}
@@ -47,8 +47,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
}
component VolumesTab: SnapLayout {
orientation: Qt.Vertical
component VolumesTab: ColumnLayout {
spacing: 12
CustomRect {
@@ -58,15 +57,14 @@ orientation: Qt.Vertical
color: Colors.tPalette.m3surfaceContainer
radius: root.rounding - vol.anchors.margins
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
anchors.topMargin: Tokens.padding.small
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -84,7 +82,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
spacing: Tokens.spacing.largeIncreased
CustomMouseArea {
@@ -103,7 +101,8 @@ orientation: Qt.Vertical
value: Audio.volume
Behavior on value {
Anim {}
Anim {
}
}
onInteraction: value => Audio.setVolume(value)
@@ -124,7 +123,7 @@ orientation: Qt.Vertical
}
}
CustomRect {
CustomClippingRect {
Layout.fillWidth: true
Layout.preferredHeight: 65 + Tokens.spacing.small * 2
Layout.topMargin: root.topMargin
@@ -137,34 +136,29 @@ orientation: Qt.Vertical
node: Audio.source
}
ClipRect {
anchors.fill: parent
radius: parent.radius
CustomRect {
id: sourcePeakFill
CustomRect {
id: sourcePeakFill
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
color: Qt.alpha(Colors.palette.m3primary, 0.15)
implicitWidth: parent.width * sourcePeak.peak
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
color: Qt.alpha(Colors.palette.m3primary, 0.15)
implicitWidth: parent.width * sourcePeak.peak
Behavior on implicitWidth {
Anim {}
Behavior on implicitWidth {
Anim {
}
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
anchors.topMargin: Tokens.padding.small
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -182,7 +176,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
spacing: Tokens.spacing.largeIncreased
CustomMouseArea {
@@ -201,7 +195,8 @@ orientation: Qt.Vertical
value: Audio.sourceVolume
Behavior on value {
Anim {}
Anim {
}
}
onInteraction: value => Audio.setSourceVolume(value)
@@ -235,7 +230,7 @@ orientation: Qt.Vertical
model: Audio.streams.filter(s => s.isSink)
CustomRect {
CustomClippingRect {
id: appBox
required property int index
@@ -253,21 +248,17 @@ orientation: Qt.Vertical
node: appBox.modelData
}
ClipRect {
anchors.fill: parent
radius: parent.radius
CustomRect {
id: peakFill
CustomRect {
id: peakFill
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
color: Qt.alpha(Colors.palette.m3primary, 0.15)
implicitWidth: parent.width * peak.peak
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
color: Qt.alpha(Colors.palette.m3primary, 0.15)
implicitWidth: parent.width * peak.peak
Behavior on implicitWidth {
Anim {}
Behavior on implicitWidth {
Anim {
}
}
}
@@ -280,15 +271,14 @@ orientation: Qt.Vertical
text: Audio.getStreamName(appBox.modelData)
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
anchors.bottomMargin: Tokens.padding.small
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
anchors.topMargin: Tokens.padding.small
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -307,7 +297,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
spacing: Tokens.spacing.largeIncreased
CustomMouseArea {
@@ -326,7 +316,8 @@ orientation: Qt.Vertical
value: appBox.modelData.audio.volume
Behavior on value {
Anim {}
Anim {
}
}
onInteraction: value => Audio.setStreamVolume(appBox.modelData, value)
+385
View File
@@ -0,0 +1,385 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import QtQml.Models
import Quickshell
import Quickshell.Bluetooth
import ZShell.Components
import ZShell.Config
import qs.Services
import qs.Components
import qs.Helpers
CustomClippingRect {
id: root
readonly property list<var> btConnected: Bluetooth.devices.values.filter(d => d.connected)
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
implicitWidth: 500
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.larger
spacing: Tokens.spacing.extraSmall / 2
CustomText {
Layout.rightMargin: Tokens.padding.extraSmall
Layout.topMargin: Tokens.padding.normal
font.pointSize: Tokens.font.size.large
text: qsTr("Bluetooth")
}
Toggle {
checked: Bluetooth.defaultAdapter?.enabled ?? false // qmllint disable unresolved-type
first: true
subtext: qsTr("Toggle bluetooth device state")
text: checked ? qsTr("Enabled") : qsTr("Disabled")
onToggled: {
const adapter = Bluetooth.defaultAdapter; // qmllint disable unresolved-type
if (adapter)
adapter.enabled = checked;
}
}
Toggle {
checked: Bluetooth.defaultAdapter?.discovering ?? false // qmllint disable unresolved-type
last: root.btConnected.length === 0
subtext: qsTr("Enable scanning for new devices")
text: qsTr("Discover")
onToggled: {
const adapter = Bluetooth.defaultAdapter; // qmllint disable unresolved-type
if (adapter)
adapter.discovering = checked;
}
}
ListView {
id: rows
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
interactive: false
section.property: "connected"
spacing: Tokens.spacing.extraSmall / 2
add: Transition {
Anim {
from: 0
property: "opacity"
to: 1
}
}
delegate: DelegateChooser {
role: "isDivider"
DelegateChoice {
roleValue: true
delegate: StatusDivider {
}
}
DelegateChoice {
delegate: BluetoothItem {
list: rows
width: rows.width
}
}
}
displaced: Transition {
Anim {
easing.type: Easing.OutCubic
property: "y"
}
}
model: ScriptModel {
objectProp: "address"
values: {
const byName = (a, b) => a.name.localeCompare(b.name);
return [...[...Bluetooth.devices.values].filter(d => d.connected).sort(byName).slice(0, 5),
{
isDivider: true
},
...[...Bluetooth.devices.values].filter(d => !d.connected).sort(byName).slice(0, 5)];
}
}
move: Transition {
Anim {
easing.type: Easing.OutCubic
property: "y"
}
}
remove: Transition {
Anim {
property: "opacity"
to: 0
}
}
section.delegate: Rectangle {
required property string section
color: "transparent"
height: childrenRect.height
width: ListView.view.width
CustomText {
text: parent.section
}
}
}
}
component BluetoothItem: ConnectedRect {
id: btItem
readonly property int connectedCount: root.btConnected.length
readonly property bool connecting: Network.connectingNetwork === modelData
property int horizontalPadding: Tokens.padding.largeIncreased
readonly property bool inConnectedGroup: index < connectedCount
required property int index
required property ListView list
readonly property bool loading: modelData.state === BluetoothDeviceState.Connecting || modelData.state === BluetoothDeviceState.Disconnecting // qmllint disable unresolved-type
required property BluetoothDevice modelData
property int verticalPadding: Tokens.padding.smaller
first: !inConnectedGroup && index === connectedCount + 1
implicitHeight: rowLayout.implicitHeight + verticalPadding * 2
last: inConnectedGroup ? index === connectedCount - 1 : index === list.count - 1
radius: Tokens.rounding.small
Timer {
interval: 50
running: btItem.ListView.delayRemove
onTriggered: btItem.ListView.delayRemove = false
}
Connections {
function onConnectedChanged(): void {
if (!btItem.modelData.connected)
btItem.ListView.delayRemove = true;
}
function onPairedChanged(): void {
if (btItem.modelData.paired)
btItem.modelData.connect();
}
target: btItem.modelData
}
RowLayout {
id: rowLayout
anchors.fill: parent
anchors.leftMargin: btItem.horizontalPadding
anchors.rightMargin: btItem.horizontalPadding
Column {
id: column
Layout.fillWidth: true
CustomText {
Layout.fillWidth: true
Layout.leftMargin: Tokens.spacing.extraSmall
Layout.rightMargin: Tokens.spacing.extraSmall
elide: Text.ElideRight
text: btItem.modelData.name
}
CustomText {
id: subtext
anchors.left: parent.left
anchors.right: parent.right
color: Colors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Tokens.font.size.small
text: btItem.modelData.connected ? (btItem.modelData.batteryAvailable ? qsTr("%1 battery left").arg(Math.round(btItem.modelData.battery * 100) + "%") : qsTr("Battery status unknown")) : btItem.modelData.address
}
}
Item {
Layout.alignment: Qt.AlignRight
implicitHeight: icon.height
implicitWidth: icon.width
MaterialIcon {
id: icon
font.pointSize: Tokens.font.size.large
opacity: btItem.connecting ? 0 : 1
text: btItem.modelData.batteryAvailable ? Icons.getBatteryIcon(btItem.modelData.battery) : "battery_unknown"
visible: btItem.modelData.state === BluetoothDeviceState.Connected // qmllint disable unresolved-type
Behavior on opacity {
Anim {
}
}
}
Loader {
active: opacity > 0
anchors.fill: parent
opacity: btItem.connecting ? 1 : 0
Behavior on opacity {
Anim {
}
}
sourceComponent: CircularIndicator {
bgColor: "transparent"
running: true
}
}
}
ButtonRow {
spacing: Tokens.spacing.small
IconTextButton {
font.pointSize: Tokens.font.size.small
icon: btItem.modelData.connected ? "link_off" : btItem.modelData.paired ? "link" : "add_link"
text: btItem.modelData.connected ? qsTr("Disconnect") : btItem.modelData.paired ? qsTr("Connect") : qsTr("Pair")
onClicked: {
if (btItem.modelData.connected)
btItem.modelData.disconnect();
else if (btItem.modelData.paired)
btItem.modelData.connect();
else if (!btItem.modelData.paired)
btItem.modelData.pair();
else if (btItem.modelData.pairing)
btItem.modelData.cancelPair();
}
}
}
}
}
component ConnectedRect: CustomRect {
id: bg
property bool first
property bool last
bottomLeftRadius: last ? Tokens.rounding.large : Tokens.rounding.extraSmall
bottomRightRadius: last ? Tokens.rounding.large : Tokens.rounding.extraSmall
color: Colors.tPalette.m3surfaceContainer
topLeftRadius: first ? Tokens.rounding.large : Tokens.rounding.extraSmall
topRightRadius: first ? Tokens.rounding.large : Tokens.rounding.extraSmall
Behavior on bottomLeftRadius {
Anim {
}
}
Behavior on bottomRightRadius {
Anim {
}
}
Behavior on topLeftRadius {
Anim {
}
}
Behavior on topRightRadius {
Anim {
}
}
}
component StatusDivider: CustomText {
bottomPadding: Tokens.spacing.extraSmall
color: Colors.palette.m3onSurfaceVariant
font.pointSize: Tokens.font.size.smaller
text: {
const devices = Bluetooth.devices.values; // qmllint disable unresolved-type
const connectedCount = devices.filter(d => d.connected).length;
let available = qsTr("%1 device%2 available").arg(devices.length - connectedCount).arg(devices.length === 1 ? "" : "s");
return available;
}
topPadding: Tokens.spacing.small
}
component Toggle: CustomSwitch {
id: toggleItem
readonly property alias bg: bg
property alias first: bg.first
property alias last: bg.last
property string subtext
Layout.fillWidth: true
cLayer: 2
horizontalPadding: Tokens.padding.largeIncreased
implicitHeight: Math.max(implicitContentHeight, implicitIndicatorHeight) + verticalPadding * 2
implicitWidth: implicitContentWidth + implicitIndicatorWidth + horizontalPadding * 2
indicator.anchors.right: right
indicator.anchors.rightMargin: toggleItem.horizontalPadding
indicator.anchors.verticalCenter: verticalCenter
verticalPadding: Tokens.padding.normal
background: ConnectedRect {
id: bg
StateLayer {
id: stateLayer
manualPressOverride: toggleItem.pressed
}
}
contentItem: Item {
anchors.left: parent.left
anchors.leftMargin: toggleItem.horizontalPadding
anchors.right: toggleItem.indicator.left
anchors.rightMargin: Tokens.spacing.normal
implicitHeight: column.implicitHeight
implicitWidth: column.implicitWidth
Column {
id: column
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 0
CustomText {
id: label
anchors.left: parent.left
anchors.right: parent.right
elide: Text.ElideRight
font: {
const f = Qt.font(label.font);
f.pointSize = Tokens.font.size.smaller;
return f;
}
text: toggleItem.text
}
CustomText {
id: subtext
anchors.left: parent.left
anchors.right: parent.right
color: Colors.palette.m3outline
elide: Text.ElideRight
font: {
const f = Qt.font(subtext.font);
f.pointSize = Tokens.font.size.small;
return f;
}
text: toggleItem.subtext
visible: toggleItem.subtext
}
}
}
onPressed: stateLayer.press(stateLayer.mouseX, stateLayer.mouseY)
}
}
+4 -4
View File
@@ -4,7 +4,6 @@ import QtQuick
import Quickshell
import qs.Components
import ZShell.Config
import ZShell
Item {
id: root
@@ -37,7 +36,7 @@ Item {
const diff = parent.width - Math.floor(off + content.nonAnimWidth);
if (diff < 0)
return off + diff;
return ZUtils.snap(Math.max(off, 0), root);
return Math.floor(Math.max(off, 0));
}
y: {
if (horizontal)
@@ -47,11 +46,12 @@ Item {
const diff = parent.height - Math.floor(off + content.nonAnimHeight);
if (diff < 0)
return off + diff;
return ZUtils.snap(Math.max(off, 0), root);
return Math.max(off, 0);
}
Behavior on offsetScale {
Anim {}
Anim {
}
}
Behavior on x {
enabled: !root.horizontal || root.offsetScale < 1
+7
View File
@@ -82,6 +82,13 @@ Item {
}
}
Popout {
name: "bluetooth"
sourceComponent: BluetoothPopout {
}
}
Popout {
name: "updates"
@@ -0,0 +1,71 @@
import QtQuick
import ZShell.Config
import qs.Services
import qs.Helpers.Network
import qs.Components
CustomRect {
id: root
readonly property bool closing: PopupManager.closed
readonly property url currentPopup: PopupManager.currentPopup
property bool shouldBeVisible: loader.status === Loader.Ready
color: Qt.alpha(Colors.palette.m3shadow, 0.3)
opacity: shouldBeVisible && !closing ? 1 : 0
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
onVisibleChanged: {
if (!visible) {
PopupManager.requestClose();
PopupManager.currentPopup = "";
}
}
CustomMouseArea {
anchors.fill: parent
hoverEnabled: true
preventStealing: true
propagateComposedEvents: false
onClicked: {
const insideItemWidth = mouseX < loader.x + loader.item.width && mouseX > loader.x;
const insideItemHeight = mouseY < loader.y + loader.item.height && mouseY > loader.y;
if (insideItemHeight && insideItemWidth)
return;
PopupManager.requestClose();
}
}
Loader {
id: loader
anchors.centerIn: parent
Connections {
function onCurrentPopupChanged(): void {
if (PopupManager.currentPopup) {
loader.setSource(PopupManager.currentPopup, PopupManager.currentPopupProps);
} else {
loader.source = null;
}
}
target: PopupManager
}
}
Connections {
function onNetworkConnected(): void {
PopupManager.requestClose();
}
target: Network
}
}
+102
View File
@@ -0,0 +1,102 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Services
import qs.Components
import qs.Helpers.Network
CustomClippingRect {
id: root
required property var network
color: Colors.palette.m3surfaceContainer
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
implicitWidth: layout.implicitWidth + layout.anchors.margins * 2
radius: Tokens.rounding.large
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.extraLarge
spacing: Tokens.spacing.medium
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
font.pointSize: Tokens.font.size.extraLarge * 2
text: "lock"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3onSurfaceVariant
text: qsTr("Connect to %1").arg(root.network.name)
}
CustomTextField {
id: passwordField
Layout.fillWidth: true
Layout.preferredWidth: 400
echoMode: CustomTextField.Password
errorText: qsTr("Failed to connect with given password")
isError: Network.failedNetwork
leadingIcon: "lock"
passwordMaskDelay: 5000
placeholderText: qsTr("Input password")
}
ButtonRow {
id: buttonRow
Layout.fillWidth: true
spacing: Tokens.spacing.extraSmall
IconTextButton {
fillWidth: true
font.pointSize: Tokens.font.size.normal
icon: "close"
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 2)
inactiveOnColor: Colors.palette.m3onSurfaceVariant
isRound: true
isToggle: false
shapeMorph: true
text: "Cancel"
onClicked: PopupManager.requestClose()
}
IconTextButton {
fillWidth: true
font.pointSize: Tokens.font.size.normal
icon: Network.connectingNetwork ? "" : "check"
inactiveColor: Network.connectingNetwork ? Colors.palette.m3primaryContainer : Network.failedNetwork ? Colors.palette.m3error : Colors.palette.m3primary
inactiveOnColor: Network.connectingNetwork ? Colors.palette.m3onPrimaryContainer : Network.failedNetwork ? Colors.palette.m3onError : Colors.palette.m3onPrimary
isRound: true
isToggle: false
shapeMorph: true
text: Network.connectingNetwork ? "" : "Apply"
onClicked: Network.requestConnect(root.network, passwordField.text)
Loader {
active: opacity > 0
anchors.centerIn: parent
opacity: Network.connectingNetwork ? 1 : 0
Behavior on opacity {
Anim {
}
}
sourceComponent: CircularIndicator {
bgColor: "transparent"
implicitSize: buttonRow.height - Tokens.padding.normal
running: true
}
}
}
}
}
}
@@ -0,0 +1,22 @@
pragma Singleton
import Quickshell
import QtQuick
Singleton {
id: root
property bool closed: true
property url currentPopup: ""
property var currentPopupProps: ({})
function requestClose(): void {
closed = true;
}
function requestOpen(source: url, properties = {}): void {
currentPopupProps = properties;
currentPopup = source;
closed = false;
}
}
+122 -18
View File
@@ -1,38 +1,142 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Networking
import QtQuick
import QtQuick.Layouts
import Quickshell
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Modules
import qs.Helpers as Helpers
import qs.Services
import qs.Modules.Settings.Common
import qs.Modules.Bar.Popouts.Network
import qs.Components
import qs.Helpers.Network
Item {
CustomClippingRect {
id: root
required property var wrapper
SnapLayout {
orientation: Qt.Vertical
id: layout
anchors.horizontalCenter: parent.horizontalCenter
implicitHeight: networkPopContent.height + networkPopContent.anchors.margins * 2
implicitWidth: 500 + 8 * 2
radius: (20 - Tokens.padding.small) * Tokens.rounding.scale
spacing: 8
Component.onCompleted: Network.active = true
Component.onDestruction: Network.active = false
Repeater {
model: Helpers.Network.devices
ColumnLayout {
id: networkPopContent
CustomRadioButton {
id: network
anchors.left: parent.left
anchors.margins: Tokens.padding.large
anchors.right: parent.right
anchors.top: parent.top
spacing: Tokens.spacing.extraSmall / 2
required property NetworkDevice modelData
CustomText {
Layout.preferredHeight: visible ? implicitHeight : 0
Layout.rightMargin: Tokens.padding.extraSmall
font.pointSize: Tokens.font.size.large
text: qsTr("Wifi")
}
checked: Helpers.Network.activeDevice?.name === modelData.name
text: modelData.description
visible: modelData.name !== "lo"
Toggle {
Layout.preferredHeight: visible ? implicitHeight : 0
checked: Network.wifiEnabled
first: true
last: Network.connectedNetworks.length === 0
subtext: qsTr("Toggle WiFi device state")
text: checked ? qsTr("Enabled") : qsTr("Disabled")
onToggled: Network.setWifi(checked)
}
ListView {
id: rows
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
interactive: false
section.property: "connected"
spacing: Tokens.spacing.extraSmall / 2
add: Transition {
Anim {
from: 0
property: "opacity"
to: 1
}
}
delegate: DelegateChooser {
role: "isDivider"
DelegateChoice {
roleValue: true
delegate: NetworkDivider {
}
}
DelegateChoice {
delegate: NetworkItem {
list: rows
width: rows.width
}
}
}
displaced: Transition {
Anim {
easing.type: Easing.OutCubic
property: "y"
}
}
model: ScriptModel {
values: {
const byStrengthName = (a, b) => b.signalStrength - a.signalStrength || a.name.localeCompare(b.name);
const cNetworks = [...Network.connectedNetworks];
const kNetworks = [...Network.knownNetworks];
const uNetworks = [...Network.unknownNetworks];
return [...cNetworks.sort(byStrengthName), ...(kNetworks.length > 0 ? [
{
isDivider: true,
type: "known"
},
...kNetworks.sort(byStrengthName)] : []), ...(uNetworks.length > 0 ? [
{
isDivider: true,
type: "unknown"
},
...uNetworks.sort(byStrengthName)] : [])];
}
}
move: Transition {
Anim {
easing.type: Easing.OutCubic
property: "y"
}
}
remove: Transition {
Anim {
property: "opacity"
to: 0
}
}
section.delegate: Rectangle {
required property string section
color: "transparent"
height: childrenRect.height
width: ListView.view.width
CustomText {
text: parent.section
}
}
}
}
NetworkOverlay {
anchors.fill: parent
}
}
+1 -3
View File
@@ -4,7 +4,6 @@ import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import QtQuick.Controls
import QtQuick.Effects
import qs.Components
@@ -48,8 +47,7 @@ StackView {
duration: 0
}
}
component SubMenu: SnapLayout {
orientation: Qt.Vertical
component SubMenu: ColumnLayout {
id: menu
required property QsMenuHandle handle
+1 -2
View File
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell.Services.UPower
import ZShell.Config
import qs.Modules.Bar.Components.Common
@@ -36,7 +35,7 @@ Column {
Repeater {
model: Battery.allPeripherals
SnapLayout {
RowLayout {
id: layout
required property var modelData
+4 -7
View File
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import ZShell.Config
import qs.Components
@@ -10,7 +9,7 @@ import qs.Modules
import qs.Helpers
import qs.Services
CustomRect {
CustomClippingRect {
id: root
readonly property bool hasUpdates: Object.keys(Updates.updates)?.length > 0
@@ -74,7 +73,6 @@ CustomRect {
implicitHeight: Math.min(contentHeight, (root.itemHeight + spacing) * 5 - spacing)
implicitWidth: contentWidth
spacing: Tokens.spacing.medium
clip: true
delegate: CustomRect {
id: update
@@ -87,7 +85,7 @@ CustomRect {
implicitWidth: 600
radius: root.radius - Tokens.padding.extraSmall
SnapLayout {
RowLayout {
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
@@ -97,8 +95,7 @@ CustomRect {
text: "package_2"
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
Layout.fillWidth: true
CustomText {
@@ -116,7 +113,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
Layout.fillHeight: true
Layout.preferredWidth: 300
+4 -3
View File
@@ -1,8 +1,9 @@
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import QtQuick
import qs.Components
import ZShell.Config
import ZShell
Item {
id: root
@@ -27,8 +28,8 @@ Item {
detachedMode = "";
}
implicitHeight: ZUtils.snap(nonAnimHeight, root)
implicitWidth: ZUtils.snap(nonAnimWidth, root)
implicitHeight: nonAnimHeight
implicitWidth: nonAnimWidth
Behavior on implicitHeight {
enabled: root.offsetScale < 1
+5 -8
View File
@@ -4,7 +4,6 @@ import Quickshell
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import qs.Helpers
import ZShell.Config
@@ -26,7 +25,7 @@ Item {
searchField.forceActiveFocus();
}
ClipRect {
CustomClippingRect {
id: search
anchors.left: parent.left
@@ -55,7 +54,7 @@ Item {
}
}
CustomRect {
CustomClippingRect {
id: preview
anchors.bottom: parent.bottom
@@ -65,7 +64,6 @@ Item {
color: Colors.tPalette.m3surfaceContainer
implicitWidth: ClipHistory.previewIsImage ? Math.max(Math.min(imagePreview.sourceSize.width + Tokens.padding.large * 2, Config.clipboard.sizes.previewWidth), Config.clipboard.sizes.minPreviewWidth) : Math.max(Math.min(textPreviewColumn.width + textPreviewColumn.anchors.margins * 2, Config.clipboard.sizes.previewWidth), Config.clipboard.sizes.minPreviewWidth)
radius: 25
clip: true
Behavior on implicitWidth {
Anim {}
@@ -112,7 +110,7 @@ Item {
Repeater {
model: lineRow.modelData.text.split("\t").slice(1)
SnapLayout {
RowLayout {
height: lineText.height
width: lineText.height + Tokens.spacing.extraSmall
@@ -226,16 +224,15 @@ Item {
}
}
SnapLayout {
RowLayout {
anchors.fill: parent
spacing: Tokens.spacing.small
Item {
CustomClippingRect {
id: textRect
Layout.fillHeight: true
Layout.fillWidth: true
clip: true
Item {
id: textWrapper
+4 -5
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell
import qs.Components
@@ -40,8 +39,8 @@ Item {
];
return allTabs.filter(tab => tab.enabled);
}
readonly property real nonAnimHeight: ZUtils.snap(tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + viewWrapper.anchors.margins + viewWrapper.anchors.topMargin, root)
readonly property real nonAnimWidth: ZUtils.snap(view.implicitWidth + viewWrapper.anchors.margins * 2, root)
readonly property real nonAnimHeight: tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + viewWrapper.anchors.margins + viewWrapper.anchors.topMargin
readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2
required property ScreenState screenState
implicitHeight: nonAnimHeight
@@ -94,8 +93,8 @@ Item {
}
anchors.fill: parent
implicitHeight: currentItem?.height ?? currentItem?.implicitHeight ?? 0
implicitWidth: currentItem?.width ?? currentItem?.implicitWidth ?? 0
implicitHeight: currentItem?.implicitHeight ?? 0
implicitWidth: currentItem?.implicitWidth ?? 0
Repeater {
id: repeater
+75 -53
View File
@@ -1,82 +1,104 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell
import ZShell.Config
import ZShell.Components
import qs.Helpers
import qs.Components
import qs.Modules
import ZShell.Config
import qs.Modules.Dashboard.Dash
import qs.Services
SnapLayout {
orientation: Qt.Vertical
GridLayout {
id: root
readonly property bool dashboardVisible: screenState.dashboard
required property int radius
required property ScreenState screenState
spacing: ZUtils.snap(Tokens.spacing.small, root)
columnSpacing: Tokens.spacing.small
rowSpacing: Tokens.spacing.small
height: ZUtils.snap(implicitHeight, root)
width: ZUtils.snap(implicitWidth, root)
ParallelAnimation {
id: openAnim
SnapLayout {
Layout.fillWidth: true
spacing: parent.spacing
Rect {
id: weatherRect
Layout.fillHeight: true
Layout.preferredWidth: ZUtils.snap(Tokens.sizes.dashboard.weatherWidth, root)
radius: root.radius
Weather {}
Anim {
property: "opacity"
target: root
to: 1
}
Rect {
id: userRect
Layout.preferredHeight: ZUtils.snap(user.implicitHeight, root)
Layout.preferredWidth: ZUtils.snap(user.implicitWidth, root)
radius: root.radius
User {
id: user
screenState: root.screenState
}
Anim {
property: "scale"
target: root
to: 1
}
}
SnapLayout {
Layout.fillWidth: true
spacing: parent.spacing
ParallelAnimation {
id: closeAnim
Rect {
id: calendarRect
Layout.fillWidth: true
Layout.fillHeight: true
implicitHeight: ZUtils.snap(calendar.implicitHeight, root)
radius: root.radius
Calendar {
id: calendar
screenState: root.screenState
}
Anim {
property: "opacity"
target: root
to: 0
}
Rect {
id: resourcesRect
Layout.fillHeight: true
implicitWidth: ZUtils.snap(resources.implicitWidth, root)
radius: root.radius
Anim {
property: "scale"
target: root
to: 0.9
}
}
Resources {
id: resources
}
Rect {
Layout.column: 2
Layout.columnSpan: 3
Layout.preferredHeight: user.implicitHeight
Layout.preferredWidth: user.implicitWidth
radius: root.radius
User {
id: user
screenState: root.screenState
}
}
Rect {
Layout.columnSpan: 2
Layout.fillHeight: true
Layout.preferredWidth: Tokens.sizes.dashboard.weatherWidth
Layout.row: 0
radius: root.radius
Weather {}
}
Rect {
Layout.column: 0
Layout.columnSpan: 3
Layout.fillWidth: true
Layout.preferredHeight: calendar.implicitHeight
Layout.row: 1
radius: root.radius
Calendar {
id: calendar
screenState: root.screenState
}
}
Rect {
Layout.column: 3
Layout.columnSpan: 2
Layout.fillHeight: true
Layout.preferredWidth: resources.implicitWidth
Layout.row: 1
radius: root.radius
Resources {
id: resources
}
}
+2 -4
View File
@@ -4,7 +4,6 @@ import Quickshell
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Services
@@ -118,15 +117,14 @@ CustomMouseArea {
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: inner
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.extraSmall
SnapLayout {
RowLayout {
id: monthNavigationRow
Layout.fillWidth: true
+9 -11
View File
@@ -1,7 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell
import ZShell.Services
import ZShell.Config
import qs.Components
@@ -10,8 +8,9 @@ import qs.Services
Item {
id: root
anchors.fill: parent
implicitWidth: ZUtils.snap(layout.implicitWidth + layout.anchors.margins * 2, root)
anchors.bottom: parent.bottom
anchors.top: parent.top
implicitWidth: layout.implicitWidth + layout.anchors.margins * 4
ServiceRef {
service: Storage
@@ -29,16 +28,13 @@ Item {
service: Gpu
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: layout
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.margins: Tokens.padding.large
anchors.top: parent.top
x: ZUtils.snap((root.width - implicitWidth) / 2, root)
spacing: Tokens.spacing.medium
Resource {
@@ -77,10 +73,12 @@ orientation: Qt.Vertical
required property string icon
implicitSize: ZUtils.snap((root.height - layout.anchors.margins * 2 - layout.spacing * 4) / 5, root)
Layout.fillHeight: true
implicitSize: height
Behavior on clampedVal {
Anim {}
Anim {
}
}
MaterialIcon {
+1 -1
View File
@@ -14,7 +14,7 @@ Row {
padding: 20
spacing: 12
ClipRect {
CustomClippingRect {
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
implicitHeight: info.implicitHeight
implicitWidth: info.implicitHeight
+6 -10
View File
@@ -1,8 +1,6 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import M3Shapes
import ZShell
import ZShell.Config
import qs.Modules.Dashboard.Media
import qs.Components
@@ -15,10 +13,10 @@ Item {
property ScreenState screenState
required property int radius
implicitWidth: ZUtils.snap(1000, root)
implicitHeight: ZUtils.snap(320, root)
implicitWidth: 1000
implicitHeight: 320
ClipRect {
CustomClippingRect {
anchors.fill: parent
radius: root.radius
@@ -27,7 +25,7 @@ Item {
}
}
SnapLayout {
RowLayout {
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.extraLarge
@@ -96,8 +94,7 @@ Item {
active: opacity > 0
opacity: 0
sourceComponent: SnapLayout {
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.small
MaterialShape {
@@ -143,12 +140,11 @@ orientation: Qt.Vertical
asynchronous: true
active: opacity > 0
sourceComponent: SnapLayout {
sourceComponent: RowLayout {
spacing: Tokens.spacing.extraLarge
Details {
Layout.fillWidth: true
Layout.fillHeight: true
}
LyricsAndSelector {
+154 -178
View File
@@ -1,14 +1,13 @@
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Mpris
import ZShell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
import qs.Helpers
Item {
ColumnLayout {
id: root
readonly property bool hasUnknownLength: (Players.active?.length ?? 0) > 2147483647
@@ -26,187 +25,46 @@ Item {
return `${mins}:${secs}`;
}
implicitHeight: ZUtils.snap(layout.implicitHeight, root)
implicitWidth: layout.implicitWidth
spacing: Tokens.spacing.extraSmall
SnapLayout {
orientation: Qt.Vertical
id: layout
anchors.left: parent.left
anchors.right: parent.right
y: ZUtils.snap((parent.height - implicitHeight) / 2, root)
Timer {
running: Players.active?.isPlaying ?? false
interval: Config.dashboard.mediaUpdateInterval
triggeredOnStart: true
repeat: true
onTriggered: Players.active?.positionChanged()
}
spacing: ZUtils.snap(Tokens.spacing.extraSmall, root)
CustomText {
Layout.fillWidth: true
text: Players.active?.trackTitle ?? ""
font: Tokens.font.title.large
elide: Text.ElideRight
animate: true
}
Timer {
running: Players.active?.isPlaying ?? false
interval: Config.dashboard.mediaUpdateInterval
triggeredOnStart: true
repeat: true
onTriggered: Players.active?.positionChanged()
}
CustomText {
Layout.fillWidth: true
text: Players.active?.trackArtist || qsTr("Unknown artist")
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.title.medium
elide: Text.ElideRight
animate: true
}
CustomText {
id: title
Layout.fillWidth: true
Layout.preferredHeight: ZUtils.snapCeil(implicitHeight, root)
text: Players.active?.trackTitle ?? ""
font: Tokens.font.title.large
elide: Text.ElideRight
animate: true
}
CustomText {
Layout.fillWidth: true
text: Players.active?.trackAlbum || qsTr("Unknown album")
color: Colors.palette.m3secondary
font: Tokens.font.title.medium
elide: Text.ElideRight
animate: true
}
CustomText {
id: artist
Layout.fillWidth: true
Layout.preferredHeight: ZUtils.snapCeil(implicitHeight, root)
text: Players.active?.trackArtist || qsTr("Unknown artist")
color: Colors.palette.m3onSurfaceVariant
font: Tokens.font.title.medium
elide: Text.ElideRight
animate: true
}
CustomText {
id: album
Layout.fillWidth: true
Layout.preferredHeight: ZUtils.snapCeil(implicitHeight, root)
text: Players.active?.trackAlbum || qsTr("Unknown album")
color: Colors.palette.m3secondary
font: Tokens.font.title.medium
elide: Text.ElideRight
animate: true
}
SnapLayout {
id: sliderLayout
Layout.topMargin: Tokens.spacing.extraLargeIncreased
Layout.fillWidth: true
spacing: ZUtils.snap(Tokens.spacing.small, root)
CustomText {
id: positionLabel
Layout.preferredWidth: ZUtils.snapCeil(timeMetrics.width, root)
Layout.preferredHeight: positionSlider.implicitHeight
text: root.lengthStr(Players.active?.position ?? -1)
color: Colors.palette.m3onSurfaceVariant
font: timeMetrics.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
CustomSlider {
id: positionSlider
Layout.fillWidth: true
Layout.preferredHeight: ZUtils.snap(implicitHeight, root)
value: Players.active ? Players.active.position / (Players.active.length || 1) : 0
enabled: (Players.active?.canSeek ?? false) && !root.hasUnknownLength
wavy: true
animateWave: Players.active?.isPlaying ?? false
waveFrequency: 5
waveDuration: 2000
interactionOnMove: false
onInteraction: value => {
const active = Players.active;
if (active?.canSeek && active?.positionSupported)
active.position = value * active.length;
}
Binding {
target: positionLabel
property: "text"
value: root.lengthStr(positionSlider.pos * (Players.active?.length ?? 0))
when: positionSlider.dragging
}
}
CustomText {
Layout.preferredWidth: ZUtils.snapCeil(timeMetrics.width, root)
Layout.preferredHeight: positionSlider.implicitHeight
text: root.hasUnknownLength ? "--:--" : root.lengthStr(Players.active?.length ?? -1)
color: Colors.palette.m3onSurfaceVariant
font: timeMetrics.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
ButtonRow {
Layout.topMargin: Tokens.spacing.largeIncreased
Layout.fillWidth: true
spacing: Tokens.spacing.extraSmall
IconButton {
type: IconButton.Tonal
icon: "shuffle"
isRound: true
shapeMorph: true
checked: Players.active?.shuffle ?? false
font: Tokens.font.icon.builders.medium.weight(Font.Medium).build()
enabled: Players.active?.shuffleSupported
onClicked: Players.active.shuffle = !Players.active?.shuffle
implicitWidth: Math.round(implicitHeight * 0.9)
}
IconButton {
id: previousBtn
type: IconButton.Tonal
icon: "skip_previous"
isRound: true
shapeMorph: true
font: Tokens.font.icon.large
enabled: Players.active?.canGoPrevious
onClicked: Players.active?.previous()
}
IconButton {
id: playPauseBtn
icon: Players.active?.isPlaying ? "pause" : "play_arrow"
isRound: true
shapeMorph: true
fillWidth: true
checked: Players.active?.isPlaying ?? false
font: Tokens.font.icon.large
enabled: Players.active?.canTogglePlaying
onClicked: Players.active?.togglePlaying()
}
IconButton {
id: nextBtn
type: IconButton.Tonal
icon: "skip_next"
isRound: true
shapeMorph: true
font: Tokens.font.icon.large
enabled: Players.active?.canGoNext
onClicked: Players.active?.next()
}
IconButton {
type: IconButton.Tonal
icon: Players.active?.loopState === MprisLoopState.Track ? "repeat_one" : "repeat"
isRound: true
shapeMorph: true
checked: Players.active?.loopState === MprisLoopState.Track || Players.active?.loopState === MprisLoopState.Playlist
font: Tokens.font.icon.builders.medium.weight(Font.Medium).build()
enabled: Players.active?.loopSupported
onClicked: {
const state = Players.active.loopState;
if (state === MprisLoopState.None)
Players.active.loopState = MprisLoopState.Track;
else if (state === MprisLoopState.Track)
Players.active.loopState = MprisLoopState.Playlist;
else
Players.active.loopState = MprisLoopState.None;
}
implicitWidth: Math.round(implicitHeight * 0.9)
}
}
RowLayout {
Layout.topMargin: Tokens.spacing.extraLargeIncreased
Layout.fillWidth: true
spacing: Tokens.spacing.small
TextMetrics {
id: timeMetrics
@@ -214,5 +72,123 @@ orientation: Qt.Vertical
text: Players.active ? root.lengthStr(Math.max(Players.active.position, root.hasUnknownLength ? 0 : Players.active.length)).replace(/[1-9]/g, "0") : "00:00"
font: Tokens.font.label.medium
}
CustomText {
id: positionLabel
Layout.preferredWidth: timeMetrics.width
text: root.lengthStr(Players.active?.position ?? -1)
color: Colors.palette.m3onSurfaceVariant
font: timeMetrics.font
horizontalAlignment: Text.AlignHCenter
}
CustomSlider {
id: positionSlider
Layout.fillWidth: true
value: Players.active ? Players.active.position / (Players.active.length || 1) : 0
enabled: (Players.active?.canSeek ?? false) && !root.hasUnknownLength
wavy: true
animateWave: Players.active?.isPlaying ?? false
waveFrequency: 5
waveDuration: 2000
interactionOnMove: false
onInteraction: value => {
const active = Players.active;
if (active?.canSeek && active?.positionSupported)
active.position = value * active.length;
}
Binding {
target: positionLabel
property: "text"
value: root.lengthStr(positionSlider.pos * (Players.active?.length ?? 0))
when: positionSlider.dragging
}
}
CustomText {
Layout.preferredWidth: timeMetrics.width
text: root.hasUnknownLength ? "--:--" : root.lengthStr(Players.active?.length ?? -1)
color: Colors.palette.m3onSurfaceVariant
font: timeMetrics.font
horizontalAlignment: Text.AlignHCenter
}
}
ButtonRow {
Layout.topMargin: Tokens.spacing.largeIncreased
Layout.fillWidth: true
spacing: Tokens.spacing.extraSmall
IconButton {
type: IconButton.Tonal
icon: "shuffle"
isRound: true
shapeMorph: true
checked: Players.active?.shuffle ?? false
font: Tokens.font.icon.builders.medium.weight(Font.Medium).build()
enabled: Players.active?.shuffleSupported
onClicked: Players.active.shuffle = !Players.active?.shuffle
implicitWidth: Math.round(implicitHeight * 0.9)
}
IconButton {
id: previousBtn
type: IconButton.Tonal
icon: "skip_previous"
isRound: true
shapeMorph: true
font: Tokens.font.icon.large
enabled: Players.active?.canGoPrevious
onClicked: Players.active?.previous()
}
IconButton {
id: playPauseBtn
icon: Players.active?.isPlaying ? "pause" : "play_arrow"
isRound: true
shapeMorph: true
fillWidth: true
checked: Players.active?.isPlaying ?? false
font: Tokens.font.icon.large
enabled: Players.active?.canTogglePlaying
onClicked: Players.active?.togglePlaying()
}
IconButton {
id: nextBtn
type: IconButton.Tonal
icon: "skip_next"
isRound: true
shapeMorph: true
font: Tokens.font.icon.large
enabled: Players.active?.canGoNext
onClicked: Players.active?.next()
}
IconButton {
type: IconButton.Tonal
icon: Players.active?.loopState === MprisLoopState.Track ? "repeat_one" : "repeat"
isRound: true
shapeMorph: true
checked: Players.active?.loopState === MprisLoopState.Track || Players.active?.loopState === MprisLoopState.Playlist
font: Tokens.font.icon.builders.medium.weight(Font.Medium).build()
enabled: Players.active?.loopSupported
onClicked: {
const state = Players.active.loopState;
if (state === MprisLoopState.None)
Players.active.loopState = MprisLoopState.Track;
else if (state === MprisLoopState.Track)
Players.active.loopState = MprisLoopState.Playlist;
else
Players.active.loopState = MprisLoopState.None;
}
implicitWidth: Math.round(implicitHeight * 0.9)
}
}
}
+2 -5
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import ZShell.Services
import qs.Components
@@ -158,8 +157,7 @@ Item {
active: opacity > 0
opacity: 0
sourceComponent: SnapLayout {
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.large
CustomRect {
@@ -200,8 +198,7 @@ orientation: Qt.Vertical
active: opacity > 0
opacity: 0
sourceComponent: SnapLayout {
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
spacing: Tokens.spacing.small
MaterialIcon {
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Services.Mpris
import ZShell.Config
@@ -9,15 +8,14 @@ import qs.Helpers
import qs.Services
Item {
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: layout
anchors.fill: parent
anchors.leftMargin: Tokens.padding.medium
spacing: Tokens.spacing.medium
SnapLayout {
RowLayout {
Layout.bottomMargin: -Tokens.spacing.medium
spacing: Tokens.spacing.medium
z: 1
+4 -6
View File
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell
import ZShell.Blobs
import ZShell.Config
@@ -17,7 +16,7 @@ Item {
implicitWidth: btn.implicitWidth * 0.9
implicitHeight: btn.implicitHeight * 0.9
BlobGroup2 {
BlobGroup {
id: blobGroup
color: Colors.palette.m3surfaceContainerHighest
@@ -29,7 +28,7 @@ Item {
}
}
BlobRect2 {
BlobRect {
id: btnRect
anchors.fill: parent
@@ -42,7 +41,7 @@ Item {
}
}
BlobRect2 {
BlobRect {
id: rect
anchors.right: parent.right
@@ -142,9 +141,8 @@ Item {
}
]
SnapLayout {
ColumnLayout {
id: layout
orientation: Qt.Vertical
anchors.centerIn: parent
spacing: Tokens.spacing.extraSmall
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import ZShell.Config
import ZShell.Internal
@@ -2,7 +2,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Widgets
import ZShell.Config
@@ -39,7 +38,7 @@ CustomListView {
id: rowHover
}
SnapLayout {
RowLayout {
id: rowLayout
anchors.left: parent.left
@@ -47,7 +46,7 @@ CustomListView {
anchors.bottom: parent.bottom
spacing: Tokens.spacing.extraSmall / 2
ClipRect {
CustomClippingRect {
id: iconClip
Layout.fillHeight: true
+4 -6
View File
@@ -23,7 +23,7 @@ Item {
service: Memory
}
SnapLayout {
RowLayout {
id: layout
anchors.fill: parent
spacing: Tokens.spacing.medium
@@ -60,14 +60,13 @@ Item {
Layout.fillHeight: true
implicitHeight: mainLayout.implicitHeight + mainLayout.anchors.margins * 2
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: mainLayout
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: 0
SnapLayout {
RowLayout {
spacing: Tokens.spacing.small
MaterialIcon {
@@ -132,8 +131,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: infoColumn
anchors.right: parent.right
anchors.bottom: parent.bottom
+32 -57
View File
@@ -4,8 +4,6 @@ import QtQuick
import QtQuick.Layouts
import QtQuick.Templates
import Quickshell
import ZShell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
@@ -18,17 +16,9 @@ Item {
required property var tabs
readonly property alias count: bar.count
readonly property int tabIndicatorSpacing: ZUtils.snap(Tokens.spacing.small, root)
readonly property int tabIndicatorSpacing: Tokens.spacing.small
function snapLayoutHeight(v) {
const dpr = ZUtils.dprFor(root);
let h = Math.ceil(v);
while (Math.abs(h * dpr - Math.round(h * dpr)) > 1e-6)
++h;
return h;
}
implicitHeight: ZUtils.snap(bar.implicitHeight + bar.anchors.topMargin + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight, root)
implicitHeight: bar.implicitHeight + bar.anchors.topMargin + indicator.implicitHeight + indicator.anchors.topMargin + separator.implicitHeight
TabBar {
id: bar
@@ -41,11 +31,9 @@ Item {
currentIndex: root.screenState.dashboardTab
onCurrentIndexChanged: root.screenState.dashboardTab = currentIndex
topPadding: 0
bottomPadding: 0
implicitHeight: implicitContentHeight
implicitHeight: contentHeight
background: null
contentItem: SnapLayout {
contentItem: RowLayout {
spacing: 0
Repeater {
@@ -128,13 +116,10 @@ Item {
readonly property bool current: TabBar.tabBar.currentItem === this
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: 1
Layout.preferredWidth: 1 // Uniform width across all tabs
implicitWidth: implicitContentWidth
implicitHeight: implicitContentHeight
background: null
topPadding: 0
bottomPadding: 0
contentItem: CustomMouseArea {
id: mouse
@@ -146,8 +131,8 @@ Item {
root.screenState.dashboardTab = Math.max(root.screenState.dashboardTab - 1, 0);
}
implicitWidth: Math.max(icon.implicitWidth, label.implicitWidth)
implicitHeight: snapLayout.implicitHeight
implicitWidth: Math.max(icon.width, label.width)
implicitHeight: icon.height + label.height
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
@@ -161,49 +146,39 @@ Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.alignWhenCentered: false
implicitHeight: ZUtils.snap(parent.height + Tokens.sizes.dashboard.tabIndicatorSpacing * 2, stateLayer)
implicitHeight: parent.height + root.tabIndicatorSpacing * 2
radius: Tokens.rounding.medium
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurface
onClicked: {
root.screenState.dashboardTab = tab.TabBar.index;
onClicked: root.screenState.dashboardTab = tab.TabBar.index
}
MaterialIcon {
id: icon
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: label.top
text: tab.iconName
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
fill: tab.current ? 1 : 0
fontStyle: Tokens.font.icon.medium
Behavior on fill {
Anim {
type: Anim.DefaultEffects
}
}
}
SnapLayout {
id: snapLayout
anchors.fill: parent
spacing: 0
orientation: Qt.Vertical
CustomText {
id: label
MaterialIcon {
id: icon
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
text: tab.iconName
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
fill: tab.current ? 1 : 0
fontStyle: Tokens.font.icon.medium
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
Behavior on fill {
Anim {
type: Anim.DefaultEffects
}
}
}
CustomText {
id: label
text: tab.text
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
}
text: tab.text
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
}
}
}
+6 -12
View File
@@ -1,13 +1,11 @@
import QtQuick
import QtQuick.Layouts
import ZShell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
import qs.Helpers
SnapLayout {
RowLayout {
id: root
spacing: Tokens.spacing.largeIncreased
@@ -22,7 +20,7 @@ SnapLayout {
readonly property real markerX: {
const d = root.now;
return ZUtils.snap(d.getHours() + d.getMinutes() / 60, root);
return d.getHours() + d.getMinutes() / 60;
}
function formatHour(h) {
@@ -41,13 +39,11 @@ SnapLayout {
onTriggered: root.now = new Date()
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: root.width / 2
SnapLayout {
RowLayout {
Layout.fillWidth: true
MaterialIcon {
@@ -94,13 +90,11 @@ orientation: Qt.Vertical
}
}
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: root.width / 2
SnapLayout {
RowLayout {
Layout.fillWidth: true
MaterialIcon {
+7 -14
View File
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Modules.Dashboard.Weather
import qs.Services
@@ -19,14 +18,13 @@ Item {
implicitHeight: layout.implicitHeight
Component.onCompleted: Weather.reload()
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: layout
anchors.fill: parent
spacing: Tokens.spacing.medium
SnapLayout {
RowLayout {
Layout.leftMargin: Tokens.padding.large
Layout.rightMargin: Tokens.padding.large
Layout.fillWidth: true
@@ -84,7 +82,7 @@ orientation: Qt.Vertical
}
}
SnapLayout {
RowLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.medium
@@ -123,9 +121,7 @@ orientation: Qt.Vertical
color: Colors.palette.m3onSurface
}
SnapLayout {
id: forecastLayout
RowLayout {
Layout.fillWidth: true
spacing: Tokens.spacing.medium
@@ -141,14 +137,12 @@ orientation: Qt.Vertical
required property var modelData
Layout.fillWidth: true
Layout.fillHeight: true
implicitHeight: forecastItemColumn.implicitHeight + Tokens.padding.medium * 2
radius: root.radius
color: Colors.tPalette.m3surfaceContainer
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: forecastItemColumn
anchors.centerIn: parent
@@ -202,8 +196,7 @@ orientation: Qt.Vertical
property color colour
Layout.fillWidth: true
Layout.fillHeight: true
implicitHeight: 60
Layout.preferredHeight: 60
radius: Tokens.rounding.medium
color: Colors.tPalette.m3surfaceContainer
@@ -237,7 +230,7 @@ orientation: Qt.Vertical
}
}
component WeatherStat: SnapLayout {
component WeatherStat: RowLayout {
id: weatherStat
property string icon
@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Widgets
import Quickshell.Hyprland
@@ -26,7 +25,7 @@ Item {
onClicked: root.close()
}
ClipRect {
CustomClippingRect {
id: popupBackground
readonly property real padding: 4
@@ -44,8 +43,7 @@ Item {
}
opacity: root.visible ? 1 : 0
SnapLayout {
orientation: Qt.Vertical
ColumnLayout {
id: menuLayout
anchors.centerIn: parent
spacing: 0
@@ -55,7 +53,7 @@ orientation: Qt.Vertical
radius: popupBackground.radius - popupBackground.padding
implicitHeight: openTerminalRow.implicitHeight + Tokens.padding.extraSmall * 2
SnapLayout {
RowLayout {
id: openTerminalRow
spacing: 8
anchors.fill: parent
@@ -94,7 +92,7 @@ orientation: Qt.Vertical
radius: popupBackground.radius - popupBackground.padding
implicitHeight: settingsRow.implicitHeight + Tokens.padding.extraSmall * 2
SnapLayout {
RowLayout {
id: settingsRow
spacing: 8
anchors.fill: parent
@@ -134,7 +132,7 @@ orientation: Qt.Vertical
radius: popupBackground.radius - popupBackground.padding
implicitHeight: logoutRow.implicitHeight + Tokens.padding.extraSmall * 2
SnapLayout {
RowLayout {
id: logoutRow
spacing: 8
anchors.fill: parent
@@ -173,7 +171,7 @@ orientation: Qt.Vertical
// radius: popupBackground.radius - popupBackground.padding
// implicitHeight: desktopIconsRow.implicitHeight + Tokens.padding.extraSmall * 2
//
// SnapLayout {
// RowLayout {
// id: desktopIconsRow
// spacing: 8
// anchors.fill: parent
@@ -3,7 +3,6 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs.Components
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -41,7 +40,7 @@ Item {
visible: false
z: 999
ClipRect {
CustomClippingRect {
id: popupBackground
readonly property real padding: Tokens.padding.extraSmall
@@ -58,25 +57,22 @@ Item {
Anim {}
}
SnapLayout {
ColumnLayout {
id: menuLayout
anchors.centerIn: parent
spacing: 0
orientation: Qt.Vertical
CustomRect {
Layout.preferredWidth: 160
implicitHeight: openRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: openRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -115,12 +111,11 @@ Item {
implicitHeight: openWithRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: openWithRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -161,12 +156,11 @@ Item {
implicitHeight: copyPathRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: copyPathRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -196,12 +190,11 @@ Item {
radius: popupBackground.radius - popupBackground.padding
visible: contextMenu.targetPaths.length === 1
SnapLayout {
RowLayout {
id: renameRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
@@ -238,12 +231,11 @@ Item {
implicitHeight: deleteRow.implicitHeight + Tokens.padding.extraSmall * 2
radius: popupBackground.radius - popupBackground.padding
SnapLayout {
RowLayout {
id: deleteRow
anchors.fill: parent
anchors.leftMargin: Tokens.padding.small
spacing: 8
MaterialIcon {
+2 -7
View File
@@ -4,7 +4,6 @@ import Quickshell
import Quickshell.Widgets
import qs.Components
import qs.Helpers
import ZShell.Components
import ZShell.Config
import qs.Services
@@ -30,10 +29,7 @@ CustomRect {
active: !isSeparator
anchors.centerIn: parent
sourceComponent: SnapLayout {
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
sourceComponent: ColumnLayout {
IconImage {
id: icon
@@ -42,9 +38,8 @@ CustomRect {
source: Quickshell.iconPath(AppSearch.guessIcon(appToplevel?.appId), "image-missing")
}
SnapLayout {
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 3
Repeater {

Some files were not shown because too many files have changed in this diff Show More