mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-29 06:27:47 -04:00
commit f9bcdfdce1ab4a028cd9ccc08bc5fc6748e2d9e8 Author: bbedward <[email protected]> Date: Thu Sep 17 16:37:31 2026 -0400 wallpaper: regenerate colors when the active light/dark wallpaper changes commit 0b2dd37971a7b360f26b1a302297335963282313 Author: bbedward <[email protected]> Date: Thu Sep 17 16:16:03 2026 -0400 lyrics: keep the active line in place when rows above resize, remember the lyrics view commit db56722c7af9cb50a9c779a39e12a54dc5a607a6 Author: bbedward <[email protected]> Date: Thu Sep 17 16:04:33 2026 -0400 lyrics: emphasize vocals per part instead of per group commit 934e0676d9d63f6a7cb314c693ac256c1b56e057 Author: bbedward <[email protected]> Date: Thu Sep 17 15:59:56 2026 -0400 lyrics: drop focus from overlapping lines when their vocals end commit 3fe092446b1f27d7acc1a0a2a2ecc5d19f455275 Author: bbedward <[email protected]> Date: Thu Sep 17 15:17:28 2026 -0400 media: add lyrics attribution, unison provider, shrink album art slightly when its low res commit f54b3e2c1dc589451f449218d4985758b88757b4 Author: bbedward <[email protected]> Date: Thu Sep 17 14:35:52 2026 -0400 media/zurvan: style changes commit 9ea5aecfba4c638e2f08ab288706d2fb3143ea0b Author: bbedward <[email protected]> Date: Thu Sep 17 14:02:03 2026 -0400 rebase fixes commit b2b04d12d2e9118346d0e5950b348aa222d58e50 Author: bbedward <[email protected]> Date: Thu Sep 17 13:46:03 2026 -0400 i18n: overhaul battery popout: redesign clipboard: fix style of pinned button and remove number sidebar commit 3057940bb28a29de22f90f5630a2c68113707d16 Author: bbedward <[email protected]> Date: Thu Sep 17 11:48:16 2026 -0400 displayconfig: show valid fractional scales only, fix custom setter commit 2bbe9e4b4c4278d1aca8632d650feba912a1c0af Author: bbedward <[email protected]> Date: Thu Sep 17 10:47:43 2026 -0400 media/zurvan: restyle commit 33299ef45261c4f0a7e8e663c1ed2f0996e3ac78 Author: purian23 <[email protected]> Date: Thu Sep 17 02:50:08 2026 -0400 refactor(clipboard): add click to open image previews & misc adjustments commit 9809aad3c466bf4974b887a37a806039e58b47ed Author: purian23 <[email protected]> Date: Thu Sep 17 02:35:20 2026 -0400 add(media): dynamic sizing - tests: start the fixture bus with dbus-broker or dbus-daemon commit 75a20eeb5a1299af1b0dd0d99cb374b4c5c8f15f Author: purian23 <[email protected]> Date: Thu Sep 17 00:30:04 2026 -0400 fix(dash): position bar-triggered popout once commit 1536691beb0bf2cd58fa3e1b2106eeeb9317a39c Author: purian23 <[email protected]> Date: Wed Sep 16 23:58:50 2026 -0400 dash & cc: operation freedom commit f3a2ae13bffbbdb92134af23138dc9a253f69e09 Author: bbedward <[email protected]> Date: Wed Sep 16 23:12:58 2026 -0400 lyrics: keep track identity independent of mpris length commit a59dd84908486f23e07172a6fca4c76eed27d31f Author: bbedward <[email protected]> Date: Wed Sep 16 22:41:44 2026 -0400 more zurvan changes commit fda890225576e6fc740946486c5c05cdc58ebd77 Author: bbedward <[email protected]> Date: Wed Sep 16 22:10:55 2026 -0400 media: more style changes commit 2170f055e3700466f87c0f6a072cb67e5e610574 Author: bbedward <[email protected]> Date: Wed Sep 16 20:00:36 2026 -0400 zurvan style tweaks commit 10795b2f2c41fcd1c24f5625324ff0ea7dd3e4ae Author: bbedward <[email protected]> Date: Wed Sep 16 18:32:48 2026 -0400 media: adjust styling of zurvan player commit 363eb10f7f53681d8f36fc6e9648205c9d5879d2 Author: bbedward <[email protected]> Date: Wed Sep 16 17:30:05 2026 -0400 lyrics: dont classify 401s as failures commit 0267c7110e14285fe4a611dbc78aee93e77e6ec8 Author: bbedward <[email protected]> Date: Wed Sep 16 17:07:34 2026 -0400 media: create the dank lyrics engine with multiple providers and priority support media: add zurvan style player and make it default commit 0aae835377cc96c5ec8383650df914058f604a42 Author: bbedward <[email protected]> Date: Wed Sep 16 10:22:36 2026 -0400 remove dumb test commit 8610121b1cb20b4b4b557170b7df52af39f4efff Author: bbedward <[email protected]> Date: Wed Sep 16 10:16:00 2026 -0400 notifications: redesign card header commit 868b73740a575d51577fa3aaff5abc1ccd53043c Author: bbedward <[email protected]> Date: Wed Sep 16 09:24:13 2026 -0400 clipboard: tweak image preview style commit 6de9a1ba7c306269889227b892703dc822049ac9 Author: purian23 <[email protected]> Date: Tue Sep 15 22:52:40 2026 -0400 clipboard: new size variants & image previews commit 05909190a2fb93a3a2c68fc711c07c3ffc09a529 Author: bbedward <[email protected]> Date: Tue Sep 15 19:14:41 2026 -0400 qs: drop the delegates the layout and output migrations left behind commit 6ca48caf7c2141e7e5f55a7d4634e0803a90c6b9 Author: bbedward <[email protected]> Date: Tue Sep 15 19:03:03 2026 -0400 config: one implementation of the compositor fragment mechanics commit 9f024c001e0c661a19c35b92bb36a6a9758f9d4d Author: bbedward <[email protected]> Date: Tue Sep 15 18:34:03 2026 -0400 compositor: name capabilities instead of checking identity in the ui commit 90067f14ed38e0cbf919e35cbf333f62240bc585 Author: bbedward <[email protected]> Date: Tue Sep 15 18:19:57 2026 -0400 settings: read every default from the spec commit 7f7ae95ed3093c5df7cb4bf5d23b718497a769ff Author: bbedward <[email protected]> Date: Tue Sep 15 15:47:13 2026 -0400 notifications: watch screen sharing from the service side commit a470ed448cbddb849922e80afdd2b13eb85f08f9 Author: bbedward <[email protected]> Date: Tue Sep 15 15:15:38 2026 -0400 rebase fix commit dc8f05fa0ca4650a40e32fb59614ca1b7df75f38 Author: bbedward <[email protected]> Date: Tue Sep 15 10:57:38 2026 -0400 dash: keep cards still when edit mode opens commit bc2001359613fd9b47ba0000a8f8f081d412a166 Author: bbedward <[email protected]> Date: Tue Sep 15 10:16:48 2026 -0400 settings: own the full spec again and merge the shared greeter keys settings: drop sidebar hints that repeat their own label cc/dash: change edit interface design slightly commit ee963f54b259eced7ec23701194539441b264db0 Author: purian23 <[email protected]> Date: Mon Sep 14 23:43:56 2026 -0400 settings: update island notification handling to use bar context commit 4d6f9fde4401001625f0352f97821ce5034a7e1c Author: bbedward <[email protected]> Date: Mon Sep 14 23:21:28 2026 -0400 greeter: read the shared settings schema instead of a duplicated one commit 70e4bdaec84efa3d68438ef235e46762cee38101 Author: bbedward <[email protected]> Date: Mon Sep 14 22:42:31 2026 -0400 osd, toast, launcher: start open motion after onFrameSwapped signal commit ddfd28b7be6dd4b0940512897d835107dbab1f23 Author: bbedward <[email protected]> Date: Mon Sep 14 21:12:37 2026 -0400 notifications: wait for onFrameSwapped signal before showing notification popup Lets the layer-surface map before rendering the body, resulting in better animation appearance commit 24efe6f8a18b36bb42c6b399086ffa5c5e2aa9c5 Author: purian23 <[email protected]> Date: Mon Sep 14 18:55:46 2026 -0400 notifications: adjust animation durations - Mapped the layer-shell surface - Fixed group chevron/dismiss button commit 52389ecf5cc586e912c26a345004814e37f4048a Author: bbedward <[email protected]> Date: Mon Sep 14 18:10:33 2026 -0400 dash: spacing tweak of tabbart commit 0285a70c1b07d09558c450c1eeb925a5c903069f Author: bbedward <[email protected]> Date: Mon Sep 14 17:55:43 2026 -0400 blah commit a1abc7a8df94032b01b51189b214aa21543f7218 Author: bbedward <[email protected]> Date: Mon Sep 14 17:40:10 2026 -0400 shrink window CSD height commit db20f7e9bb93c7dce503e410e82e15e7a03b1e7d Author: bbedward <[email protected]> Date: Mon Sep 14 17:16:16 2026 -0400 windows: center titles commit 7268712bdf58c5c1903606f24a392d64655a4ad5 Author: purian23 <[email protected]> Date: Mon Sep 14 16:45:44 2026 -0400 notifications: updated entry/exit paths - Added popout option in island mode - Fixed cards getting stuck & out of place when multiples arise at once commit 3a3f0b3061bd0a7ce895152ec5a056600e41e7e8 Author: bbedward <[email protected]> Date: Mon Sep 14 16:34:36 2026 -0400 battery: make cc variant consistent commit ee569ddef3bf2875d42347d18b57f493f492b243 Author: bbedward <[email protected]> Date: Mon Sep 14 16:15:42 2026 -0400 battery: remove bottom text footer thing commit 817c4e46eac52c95d91f418e3ddbafdab0888b5c Author: purian23 <[email protected]> Date: Mon Sep 14 15:34:18 2026 -0400 settings: rework interface style and bar hub layouts - Separate global surface styling from per-surface overrides on Interface style - Move bar management into the hub header and render island settings inline - Cut redirect banners down to one per page and point them at the right row commit 03a4e45d65aec83c927c7419a4a0f3f252e0e955 Author: bbedward <[email protected]> Date: Mon Sep 14 14:52:20 2026 -0400 launcher: fix inconsistency in niri overview variant commit e74246d058a5db215200606eb9f9c662706d8689 Author: bbedward <[email protected]> Date: Mon Sep 14 14:21:10 2026 -0400 plugins: eval symlinks in repo lookup commit 7dd2cddebf4819da51ff7da792560372f5d9a03e Author: bbedward <[email protected]> Date: Mon Sep 14 09:09:46 2026 -0400 update common commit a8c1f77fe2d952b1ec33e622b2951e5382860c9e Author: purian23 <[email protected]> Date: Mon Sep 14 02:05:09 2026 -0400 island: fix search input focus on launcher commit 2d1f8bf5338ca5e0a4a58f0f18b54b92dfe5e5ee Author: purian23 <[email protected]> Date: Mon Sep 14 01:29:05 2026 -0400 tooltips: add further label & accessibility parity commit 3ebfe85d57553b4803b52d5e5ea417b8abec5bcf Author: bbedward <[email protected]> Date: Sun Sep 13 23:28:29 2026 -0400 ui: drop tooltips from obvious icon buttons, keep labels on Accessible.name commit a8e7a072b2bad394c5c5d9fd60eaff5240ce37d4 Author: bbedward <[email protected]> Date: Sun Sep 13 22:55:28 2026 -0400 widgets: dim filled action buttons when disabled commit 0dc58825344ebfc5479d2a3bc75b5d2ae014131a Author: bbedward <[email protected]> Date: Sun Sep 13 22:45:34 2026 -0400 settings: one compositor include workflow for outputs, layout, input, window rules, cursor and binds commit 9fc8c8e53c18de18b33ccdfe1e1abed84e01b219 Author: purian23 <[email protected]> Date: Sun Sep 13 22:27:28 2026 -0400 theme: add focus ring settings & replace text fields w/search fields aligned to m3e specs commit 8359fea68230172b1c10df08831efdf944fbbd64 Author: bbedward <[email protected]> Date: Sun Sep 13 20:37:49 2026 -0400 auth: share one pam stack parser between the greeter, lock probe and polkit commit bf05136e78aada16e41a7d0b7164a7f543d65760 Author: bbedward <[email protected]> Date: Sun Sep 13 20:24:01 2026 -0400 tests: replace golden files and dump-only fixtures with hand-written assertions commit f2cd6a877b561a5078e7b6cbad8348e9165158ca Author: bbedward <[email protected]> Date: Sun Sep 13 19:15:02 2026 -0400 display: split DisplayService into brightness, night mode and refresh rate services commit fa7ce5fe836e4f00646c80eb3cb50ecc004f4524 Author: bbedward <[email protected]> Date: Sun Sep 13 18:19:26 2026 -0400 battery: m3e redesign commit 04576106158c009374d9564d18852cf7ea1f9284 Author: bbedward <[email protected]> Date: Sun Sep 13 17:21:32 2026 -0400 shell: one window model and one keyboard layout source hosts: put change handlers on the observed object instead of proxy properties commit e4750c767b27d4650b95d42930410ad090d6ca87 Author: bbedward <[email protected]> Date: Sun Sep 13 15:39:10 2026 -0400 shell: replace connections with bound property handlers in per-item and per-screen components commit 8efb05dc014f0d09b36d6112b03e6f4e1f60d1d2 Author: bbedward <[email protected]> Date: Sun Sep 13 13:43:10 2026 -0400 display config: move output parsing, identifiers and geometry into a pure model commit e9b8174812b2da316eeae42e3989f2f269ef5649 Author: bbedward <[email protected]> Date: Sun Sep 13 12:52:46 2026 -0400 slideout: build content on first open commit b899f307650cf5cc646de90ac666b6e1731bbc4f Author: bbedward <[email protected]> Date: Sun Sep 13 12:28:11 2026 -0400 services: stop using weakmap for workspace, window and term caches commit b90e9a4c2a72744685f79cf613ab80660721389f Author: bbedward <[email protected]> Date: Sun Sep 13 10:35:48 2026 -0400 workspaces: one model with per-compositor adapters, no compositor branches in widgets shell: stop hot reload while the session lock is held commit e200e17e96e06b4fd7e0dd596b50dcbbc254494a Author: purian23 <[email protected]> Date: Sun Sep 13 02:36:41 2026 -0400 dock: mix widgets between pinned apps - Pinned apps become individual units in edit mode with a saved per-dock order, while running windows stay one unit in compositor order. - Fix the Window.window Connections crash - Add right-click-to-edit empty dock space option and dock edit / editFor ipc commands commit cad3ba78727695419a4fe8a96c90146bbf5e6120 Author: bbedward <[email protected]> Date: Sun Sep 13 00:51:35 2026 -0400 launcher: create plugin instances only when a query needs them commit aed25c3c75d0c24a17a940c162a6956a372c4e0f Author: bbedward <[email protected]> Date: Sat Sep 12 23:45:19 2026 -0400 settings: rebuild about, printer, wifi, display and window rules pages on settings blocks popouts: drop inconsistent headers commit 3a20c2c9528fe1fed3464085492af3bebdcdf809 Author: bbedward <[email protected]> Date: Sat Sep 12 17:41:18 2026 -0400 launcher: consolidate host code and logic commit 4e53b470d5beaffa54687c8164e492ee41472e49 Author: bbedward <[email protected]> Date: Sat Sep 12 15:37:44 2026 -0400 surfaces: collapse connected/standalone popout and modal hosts typography: make font weight work and follow m3 weights settings: fix reset to default shifting rows commit ce71b5dc3ca0e96ee11b906b1ea3399d3d7d93ac Author: bbedward <[email protected]> Date: Sat Sep 12 15:02:25 2026 -0400 dock: move widgets, launcher, apps and trash as units in edit mode commit 6ebaef52d885744a45f3db7d48c3b6d0924993b2 Author: bbedward <[email protected]> Date: Sat Sep 12 13:24:31 2026 -0400 plugins: add examples for dash and dock commit 067cabc95991f5676a19746d3cad0700eb525082 Author: bbedward <[email protected]> Date: Sat Sep 12 12:25:59 2026 -0400 settings: fix v18 migration commit 55d07f3bba352972c768acdd7b6705f80fac4e0f Author: bbedward <[email protected]> Date: Sat Sep 12 12:09:56 2026 -0400 ci: fix fails commit 2e81531dd6980f0331af80fe5beca1d695c58f06 Author: bbedward <[email protected]> Date: Sat Sep 12 11:49:39 2026 -0400 surfaces: add windowRadius token to make surfaces actually follow settings and match the compositor windows surfaces: change default radius (Strength 50) from 12->16 settings: add result to default for everything settings: further re-organization and re-structuring position of things settings: remove dead keys dock: remove hardcoded border and respect border setting bar: add a third style and color options ci: hookup QML testing commit a2fd8abd37e0ff1ef67af9bfa4e7679e7aa338bd Author: bbedward <[email protected]> Date: Sat Sep 12 09:20:00 2026 -0400 dash: size surface width to the width of the largest tab commit 93394549a2cb3f7647b564ba71621e113c83e106 Author: bbedward <[email protected]> Date: Sat Sep 12 00:11:15 2026 -0400 bar/workspaces: restore old style, respect color choices, make pills default > segments commit 71f8351a3b11f8d06e45dd28db4d501e54a27f9a Author: purian23 <[email protected]> Date: Fri Sep 11 23:48:04 2026 -0400 dbar: initial M3E remaster pass on shared chrome w/dock & island commit 1711716073f660afd519ab0af88d3c8177f1a8c8 Author: bbedward <[email protected]> Date: Fri Sep 11 21:44:31 2026 -0400 dash: only show focus ring when KB navigating commit 6037de06471e7fa80ec36088e9e86cbf2e4d3941 Author: bbedward <[email protected]> Date: Fri Sep 11 21:41:53 2026 -0400 launcher: scope plugin and clipboard refreshes, paint the keystroke before plugin search commit 78c9ab990b7665e76762dadd65d1a1d23275a405 Author: bbedward <[email protected]> Date: Fri Sep 11 21:16:36 2026 -0400 launcher: one open-session reset, faster keystroke settle commit 01b15051363715bfb2bfe1d905b4b573fb4e49ac Author: bbedward <[email protected]> Date: Fri Sep 11 20:47:45 2026 -0400 dash: fix kb navigation on overview commit 27465074e1fa395a844cc3b804a362ee7a4e4f70 Author: bbedward <[email protected]> Date: Fri Sep 11 16:58:53 2026 -0400 dash: replace material shapes on resource cards with a ring gauge commit 5e41b85a1df69885c57a41ab44a43ef38b0c5560 Author: bbedward <[email protected]> Date: Fri Sep 11 16:33:48 2026 -0400 qml: share bases for registry browsers, fade windows and plugin list settings Fixes fade window focus, list setting load write-back and the missing Theme.onError commit be3542ab8fc1949a256d6498b5c4a0379b86e023 Author: bbedward <[email protected]> Date: Fri Sep 11 16:11:15 2026 -0400 popout: fix pixel jumps commit 2ad0e9e2f5b12f13f0acc9733c29c4c42d640df7 Author: bbedward <[email protected]> Date: Fri Sep 11 15:52:52 2026 -0400 popout: fade the surface fill with the content commit 4b11e21b1a09895f67ca1b6b858fe772500e4a2c Author: bbedward <[email protected]> Date: Fri Sep 11 15:13:14 2026 -0400 desktop widgets: read and write saved geometry through one path commit 21ed01bbb20627d4d68bbb704b9f2bb50b45c911 Author: bbedward <[email protected]> Date: Fri Sep 11 15:10:02 2026 -0400 surfaces: bind modal and popout backends to their handle commit 362859d810b768621061f0429c39b17ff3b00184 Author: bbedward <[email protected]> Date: Fri Sep 11 14:30:27 2026 -0400 notifications: move the popup context menu onto DankContextMenu commit 8942b622f5929e854fbcf145e7f34f4637904731 Author: bbedward <[email protected]> Date: Fri Sep 11 14:20:49 2026 -0400 colorpicker: design changes consolidate context menus commit 29be554d488aefd9a8f6e4e5f5d094147e3b214d Author: bbedward <[email protected]> Date: Fri Sep 11 12:48:02 2026 -0400 dash: add analog clock option commit 43748726983a466e19e4b642399ea040d4095de9 Author: bbedward <[email protected]> Date: Fri Sep 11 12:12:51 2026 -0400 popouts: fix spacing inconsistencies dash: redesign overview media card osd: more redesign dash/overview: remove row cap and make it dynamic commit 14a3a315d94336cac6e8eb77e08965503717d780 Author: bbedward <[email protected]> Date: Fri Sep 11 09:23:53 2026 -0400 shell: dedupe bar ipc handlers, weather resets, color options, launcher icons commit 9f2b6d4bbe6f5954a33b5853ecea0ef0ac4b483e Author: purian23 <[email protected]> Date: Thu Sep 10 23:52:39 2026 -0400 dock: add spacing option & update defaults commit 3e6cb55488a42ade23728bcf4d8608efab2e6e0f Author: bbedward <[email protected]> Date: Thu Sep 10 23:29:07 2026 -0400 session: collapse the monitor cycling setters onto one helper commit 613e756d8bf88b3c2e6ae7edcede4c680da72456 Author: bbedward <[email protected]> Date: Thu Sep 10 21:56:38 2026 -0400 dock: share the hover bounce animation across dock buttons commit 8d8f801874ddf5dcc3b299405de458183e758c7c Author: bbedward <[email protected]> Date: Thu Sep 10 21:46:44 2026 -0400 settings: share one picker window for bar and desktop widgets commit e3c90efbce4d7d11adf0cceefb8e9758e7d9099c Author: bbedward <[email protected]> Date: Thu Sep 10 21:24:10 2026 -0400 network: merge wired and wifi info modals commit 43f75e6a3dfc988f3adc8c7d659fff5529ed6db8 Author: purian23 <[email protected]> Date: Thu Sep 10 21:22:06 2026 -0400 island: unify new dashboard dynamic sizing & activities - New wallpaper carousel and Colum/Row options - Fixed island controller overlap in bar widget settings - Fixed island widgets click to hide activity - Expanded island IPC cyle targets commit 805611efca91bea029894436dad9baa6dd492461 Author: bbedward <[email protected]> Date: Thu Sep 10 19:40:27 2026 -0400 bar: share context menu window and tooltip offset across widgets also fix Media art glitches and things commit 17a08c4c7e56312d0b3a7732978223f569828aaf Author: bbedward <[email protected]> Date: Thu Sep 10 19:00:48 2026 -0400 osd/media: respect follow album accent option commit 6a753a7ab6304568f178bc3ec0910a9132020dd2 Author: bbedward <[email protected]> Date: Thu Sep 10 18:57:15 2026 -0400 theme: fix surface elevation commit af4f44eba649923bfb0928423a24fc6d115518c4 Author: bbedward <[email protected]> Date: Thu Sep 10 18:45:09 2026 -0400 m3e: redesign OSDs, Forms, etc. commit 1d2add180a661157b3c06a1221edae21bdbcb765 Author: bbedward <[email protected]> Date: Thu Sep 10 17:19:07 2026 -0400 rebase fixes commit ac39a7745cfe88bcfd3826f64cfd55ed41b18b3e Author: bbedward <[email protected]> Date: Thu Sep 10 16:51:16 2026 -0400 tray: share one item delegate and icon for both bar orientations commit 642eeb0f4b5d0a912fc44c134fc10adf8a5b5291 Author: bbedward <[email protected]> Date: Thu Sep 10 16:33:36 2026 -0400 bar: share one delegate for running apps in both orientations commit 7f69e42f3bef9025d411acfc768deb3865338922 Author: bbedward <[email protected]> Date: Thu Sep 10 15:56:33 2026 -0400 bar: share one monitor pill for cpu, ram, temp and disk widgets commit f5507dc3b2df6929521e87cd820eb45a3e3077ad Author: bbedward <[email protected]> Date: Thu Sep 10 14:03:00 2026 -0400 island: reuse widget model, surface palette and layout metrics in hosts commit aceac03ba0c9a2b0aa1a47f1b62a380fc785ec6d Author: bbedward <[email protected]> Date: Thu Sep 10 13:36:47 2026 -0400 osd: share one level osd for volume, brightness, mic and media commit 1b4a68d10c5b59f3ecf3e7c44974a2cb83964246 Author: bbedward <[email protected]> Date: Thu Sep 10 13:12:30 2026 -0400 shell: consolidate connected surface state into one slot store commit d7edc23cf14a10cd275fdf3888d24482d43a15f3 Author: bbedward <[email protected]> Date: Thu Sep 10 12:19:30 2026 -0400 shell: restore centered dash popout for center-section widgets commit d2f9405de9e7ade7db402826cfb0520249c58a2b Author: bbedward <[email protected]> Date: Thu Sep 10 12:11:29 2026 -0400 dash/media: always show placeholder player when no players are playing commit 55535082f53163914440e1e858aa78246bc4e40a Author: bbedward <[email protected]> Date: Thu Sep 10 12:08:10 2026 -0400 dock: fix sizing, exclusive zone, edit mode and multi-instance settings commit c82cc738ca2d20e7a4363b7abb86ad6d9e7bb172 Author: bbedward <[email protected]> Date: Thu Sep 10 11:08:40 2026 -0400 settings/plugins: redesign page commit 9c283e0f6c4b7d812362124fdd36fc15327ef03c Author: bbedward <[email protected]> Date: Wed Sep 9 20:44:26 2026 -0400 shell: route widget instances and support same-edge layouts commit 405a3b397c264688b2271d6acec881a4aea4864f Author: bbedward <[email protected]> Date: Wed Sep 9 18:05:37 2026 -0400 shell: share bar content and clock presentation commit 65a6d2df8e870af259b1542c896fce60be4f6cb6 Author: bbedward <[email protected]> Date: Wed Sep 9 15:49:23 2026 -0400 shell: centralize layout ownership commit 585aeb4e1cba737cc4007fc214ac1e109d3e0f19 Author: purian23 <[email protected]> Date: Wed Sep 9 18:05:13 2026 -0400 dock: initial m3e remaster commit a2e646f2fb364f042fb134e74e9014386b80971b Author: bbedward <[email protected]> Date: Wed Sep 9 14:58:38 2026 -0400 plugins: consolidate upgrade path commit 139253504c5f62d522fbc6109689c11ccaec7493 Author: bbedward <[email protected]> Date: Wed Sep 9 14:43:28 2026 -0400 settings: use icons on all outlined text fields commit a9c1e569b8428e4f3748da345200e8a62c90ba20 Author: bbedward <[email protected]> Date: Wed Sep 9 14:32:33 2026 -0400 launcher: fix KB navigation focus and modes commit ac64eb52d360322a0e952844b41b58532d5ae32f Author: bbedward <[email protected]> Date: Wed Sep 9 14:05:10 2026 -0400 m3e: remove inconsistent widget usage, adjust SystemUpdater rredesign, fix window decoration inconsistencies commit 0eac1d3e22cb879c7b7e9205fba0ed9c17b89dcd Author: bbedward <[email protected]> Date: Wed Sep 9 13:25:44 2026 -0400 server: consolidate ipc routing and subscription forwarding commit ed289e5c2c867eb2d6e1319d9517885e6e80d1a3 Author: bbedward <[email protected]> Date: Wed Sep 9 12:56:29 2026 -0400 plugins: redesign management and browsers with m3 expressive commit 7f3a526e2d38c24edbb5d51c4c9c550a0bc93752 Author: bbedward <[email protected]> Date: Wed Sep 9 11:00:07 2026 -0400 settings: fix inconsistent ripple effect radius commit 8f1fb8a11e92b1811808325c136199fef10d4a53 Author: bbedward <[email protected]> Date: Wed Sep 9 10:26:39 2026 -0400 aqueous: fix variant terms commit 2ba861947092cb657d983702c842e88ffc6fb0fa Author: bbedward <[email protected]> Date: Wed Sep 9 10:01:50 2026 -0400 running apps: fix delegate bug commit b37c925e85cb6902bbb3005d92a5b522e3648116 Author: bbedward <[email protected]> Date: Wed Sep 9 00:18:57 2026 -0400 bump dml-common commit 5e83c40c56c624df74306efc839d707ec8d6aa14 Author: bbedward <[email protected]> Date: Wed Sep 9 00:12:16 2026 -0400 settings: incorporate user & accounts tab, consolidate security, add M3E textfield commit 278370c7909226ca42f0a53cbd9ca2bd5f2fb4e7 Author: bbedward <[email protected]> Date: Tue Sep 8 18:17:25 2026 -0400 m3e: unify shell surfaces and refresh process monitoring commit e2d5860d3952da717ba9073e857133f2538a70b0 Author: bbedward <[email protected]> Date: Tue Sep 8 15:15:17 2026 -0400 notifications: fix expansion timing and simplify the header commit d8f29c221474c2884ec482d26c827de09d581539 Author: bbedward <[email protected]> Date: Tue Sep 8 14:53:11 2026 -0400 icon: install app icon under the conventional name (app id) commit ebeebb70fd4c7538ef5ea867116d9fa7118eee27 Author: bbedward <[email protected]> Date: Tue Sep 8 14:47:09 2026 -0400 notifications: refine card styling and separate app icons from image previews commit d6133d93ed314ca02a9a3b634872ee32484a0bb3 Author: bbedward <[email protected]> Date: Tue Sep 8 14:27:18 2026 -0400 settings: unify expressive rows and drag and drop commit 0a4d14752a2a1e8dd60b3056fd006d02d818d6a4 Author: bbedward <[email protected]> Date: Tue Sep 8 12:32:16 2026 -0400 settings: use native action button hover state commit dc8c4564cc964ab50ed28a3e9e4ca7b13ebfbcb1 Author: bbedward <[email protected]> Date: Tue Sep 8 09:55:42 2026 -0400 shell: refine weather, slider controls, and tooltips commit bec5c6ad0119e22a3cb69975d135d3b72654f77e Author: bbedward <[email protected]> Date: Mon Sep 7 18:43:39 2026 -0400 theme: tweak token values commit 8519cbc4bbb396a8b6779764ff0f5a0945156dcf Author: bbedward <[email protected]> Date: Mon Sep 7 13:43:53 2026 -0400 dankdash: fix grid sizing, controls, notifications, and popout blur commit f2405f2925aa63eba480cff4ddc55119818f8057 Author: bbedward <[email protected]> Date: Mon Sep 7 10:38:07 2026 -0400 dash: redesign media player and migrate its appearance options commit cb57ce04fbd50920a17d9a8ad33e4d20fc856021 Author: bbedward <[email protected]> Date: Mon Sep 7 09:07:01 2026 -0400 lock: add lock m3e redesign commit e89909e3743993dad1bdf17d57ab17f1122dfa3c Author: bbedward <[email protected]> Date: Sun Sep 6 21:24:48 2026 -0400 qs: more loaders, less repetition commit 288335fef67b523f51e22bb234c81bd8b88e7e2c Author: bbedward <[email protected]> Date: Sun Sep 6 20:16:41 2026 -0400 launcher: initial m3e redesign commit 5b7fc75c473491bf086b65a41416325697ae330c Author: purian23 <[email protected]> Date: Sun Sep 6 19:50:14 2026 -0400 feat(motion): new fluid animation variant - Refactored Popouts/Modals for performance passes commit 0fc4f51f4d0b1d297c1886b19be8062d279c505b Author: bbedward <[email protected]> Date: Sun Sep 6 15:36:22 2026 -0400 notifications: tweak animnation stacking behavior on popups commit 4369233794e3bebd890a2b830c6450d0a65eb31a Author: bbedward <[email protected]> Date: Sun Sep 6 15:15:55 2026 -0400 notifications: initial M3E redesign commit eb67a51779c543038ad885ecd406bfe21aecd1e2 Author: bbedward <[email protected]> Date: Sat Sep 5 15:10:37 2026 -0400 ddash: exhaustive overhaul of even more pieces of the system commit 14554a39effd677206f7a3c4b5944d2ae47c2b03 Author: bbedward <[email protected]> Date: Sat Sep 5 12:47:06 2026 -0400 settings: rebase fixes commit d6e0bb604bdb15ed94d77f9e1d85a26381ed6836 Author: bbedward <[email protected]> Date: Sat Sep 5 10:18:38 2026 -0400 ddash: initial rewrite commit 29903114d0d8849b25c6f6e9161765b0ad03da49 Author: bbedward <[email protected]> Date: Fri Sep 4 16:48:23 2026 -0400 cc: tweak s lider size commit 8d14a07864972e4b705e77b371d21f5fdb7c4c07 Author: bbedward <[email protected]> Date: Fri Sep 4 16:44:53 2026 -0400 cc: initial M3E re-design commit 976f968967166c61cec423f3bb3f7a28a5a9ac76 Author: bbedward <[email protected]> Date: Fri Sep 4 15:00:35 2026 -0400 settings: continue to iterate commit a99a1c5ad183e34435a20dd90f19ed84099a1070 Author: bbedward <[email protected]> Date: Fri Sep 4 09:44:55 2026 -0400 stash m3e work
2476 lines
106 KiB
QML
2476 lines
106 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtCore
|
|
import QtQuick
|
|
import "../DankCommon/Common/Shape.js" as Shape
|
|
import "../DankCommon/Common/Surface.js" as Surface
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs.Common
|
|
import qs.DankCommon.Common as DankCommon
|
|
import qs.Services
|
|
import qs.Modules.Greetd
|
|
import "StockThemes.js" as StockThemes
|
|
import "GSettings.js" as GSettings
|
|
|
|
Singleton {
|
|
id: root
|
|
readonly property var log: Log.scoped("Theme")
|
|
|
|
readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell"
|
|
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
|
|
readonly property string defaultFontFamily: "Google Sans Flex"
|
|
readonly property string defaultMonoFontFamily: "Fira Code"
|
|
readonly property string defaultDisplayFontFamily: "DM Serif Display"
|
|
|
|
readonly property real popupDistance: {
|
|
if (typeof SettingsData === "undefined")
|
|
return 4;
|
|
const defaultBar = SettingsData.getPrimaryBarConfig();
|
|
if (!defaultBar)
|
|
return 4;
|
|
const useAuto = defaultBar.popupGapsAuto ?? true;
|
|
const manualValue = defaultBar.popupGapsManual ?? 4;
|
|
const spacing = defaultBar.spacing ?? 4;
|
|
return useAuto ? Math.max(4, spacing) : manualValue;
|
|
}
|
|
|
|
property string currentTheme: "purple"
|
|
property string currentThemeCategory: "generic"
|
|
property bool isLightMode: typeof SessionData !== "undefined" ? SessionData.isLightMode : false
|
|
property bool colorsFileLoadFailed: false
|
|
|
|
readonly property string dynamic: "dynamic"
|
|
readonly property string custom: "custom"
|
|
|
|
readonly property string homeDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.HomeLocation))
|
|
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
|
|
readonly property string shellDir: Paths.strip(Qt.resolvedUrl(".").toString()).replace("/Common/", "")
|
|
readonly property string wallpaperPath: {
|
|
if (typeof SessionData === "undefined")
|
|
return "";
|
|
|
|
var monitors = SessionData.monitorWallpapers;
|
|
if (SessionData.perMonitorWallpaper) {
|
|
var screens = Quickshell.screens;
|
|
if (screens.length > 0) {
|
|
var s = screens[0];
|
|
return monitors[s.name] || (s.model ? monitors[s.model] : "") || SessionData.wallpaperPath;
|
|
}
|
|
}
|
|
|
|
return SessionData.wallpaperPath;
|
|
}
|
|
readonly property string rawWallpaperPath: {
|
|
if (typeof SessionData === "undefined")
|
|
return "";
|
|
|
|
var monitors = SessionData.monitorWallpapers;
|
|
if (SessionData.perMonitorWallpaper) {
|
|
var screens = Quickshell.screens;
|
|
if (screens.length > 0) {
|
|
var targetMonitor = (typeof SettingsData !== "undefined" && SettingsData.matugenTargetMonitor && SettingsData.matugenTargetMonitor !== "") ? SettingsData.matugenTargetMonitor : screens[0].name;
|
|
|
|
var targetMonitorExists = false;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
if (screens[i].name === targetMonitor) {
|
|
targetMonitorExists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!targetMonitorExists)
|
|
targetMonitor = screens[0].name;
|
|
|
|
var s = null;
|
|
for (var j = 0; j < screens.length; j++) {
|
|
if (screens[j].name === targetMonitor) {
|
|
s = screens[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (s)
|
|
return monitors[s.name] || (s.model ? monitors[s.model] : "") || SessionData.wallpaperPath;
|
|
return monitors[targetMonitor] || SessionData.wallpaperPath;
|
|
}
|
|
}
|
|
|
|
return SessionData.wallpaperPath;
|
|
}
|
|
|
|
property bool matugenAvailable: false
|
|
property var workerRunning: false
|
|
property var pendingThemeRequest: null
|
|
|
|
signal matugenCompleted(string mode, string result)
|
|
property var matugenColors: ({})
|
|
property var _pendingGenerateParams: null
|
|
property int _colorsRetryCount: 0
|
|
property double _lastGenerateMs: 0
|
|
|
|
property bool blurLayersActive: false
|
|
property bool matugenToastSuppressed: false
|
|
|
|
signal screenTransitionNeeded
|
|
signal themeGenerationStarting
|
|
|
|
readonly property var dank16: {
|
|
const raw = matugenColors?.dank16;
|
|
if (!raw)
|
|
return null;
|
|
|
|
const dark = {};
|
|
const light = {};
|
|
const def = {};
|
|
|
|
for (let i = 0; i < 16; i++) {
|
|
const key = "color" + i;
|
|
const c = raw[key];
|
|
if (!c)
|
|
continue;
|
|
dark[key] = c.dark;
|
|
light[key] = c.light;
|
|
def[key] = c.default;
|
|
}
|
|
|
|
return {
|
|
dark,
|
|
light,
|
|
"default": def
|
|
};
|
|
}
|
|
property var customThemeData: null
|
|
property var customThemeRawData: null
|
|
readonly property var currentThemeVariants: customThemeRawData?.variants || null
|
|
readonly property string currentThemeId: customThemeRawData?.id || ""
|
|
|
|
Component.onCompleted: {
|
|
Quickshell.execDetached(["mkdir", "-p", stateDir]);
|
|
Proc.runCommand("matugenCheck", ["sh", "-c", "command -v matugen"], (output, code) => {
|
|
matugenAvailable = (code === 0) && !envDisableMatugen;
|
|
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
|
|
|
|
if (!matugenAvailable || isGreeterMode) {
|
|
return;
|
|
}
|
|
|
|
if (colorsFileLoadFailed && currentTheme === dynamic && rawWallpaperPath) {
|
|
log.info("Matugen now available, regenerating colors for dynamic theme");
|
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode);
|
|
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default";
|
|
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot";
|
|
if (rawWallpaperPath.startsWith("#")) {
|
|
setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType);
|
|
} else {
|
|
setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode);
|
|
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default";
|
|
|
|
if (currentTheme === dynamic) {
|
|
if (rawWallpaperPath) {
|
|
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot";
|
|
if (rawWallpaperPath.startsWith("#")) {
|
|
setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType);
|
|
} else {
|
|
setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType);
|
|
}
|
|
}
|
|
} else if (currentTheme !== "custom") {
|
|
const darkTheme = StockThemes.getThemeByName(currentTheme, false);
|
|
const lightTheme = StockThemes.getThemeByName(currentTheme, true);
|
|
if (darkTheme && darkTheme.primary) {
|
|
const stockColors = buildMatugenColorsFromTheme(darkTheme, lightTheme);
|
|
const themeData = isLight ? lightTheme : darkTheme;
|
|
setDesiredTheme("hex", themeData.primary, isLight, iconTheme, themeData.matugen_type, stockColors);
|
|
}
|
|
}
|
|
}, 0);
|
|
if (typeof SessionData !== "undefined") {
|
|
SessionData.isLightModeChanged.connect(root.onLightModeChanged);
|
|
}
|
|
|
|
if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) {
|
|
switchTheme(SettingsData.currentThemeName, false, false);
|
|
const currentIsLight = (typeof SessionData !== "undefined") ? SessionData.isLightMode : false;
|
|
SettingsData.updateCosmicThemeMode(currentIsLight);
|
|
}
|
|
}
|
|
|
|
function getMatugenColor(path, fallback) {
|
|
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark";
|
|
return getMatugenColorForMode(colorMode, path, fallback);
|
|
}
|
|
|
|
function getMatugenColorForMode(colorMode, path, fallback) {
|
|
let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode];
|
|
for (const part of path.split(".")) {
|
|
if (!cur || typeof cur !== "object" || !(part in cur))
|
|
return fallback;
|
|
cur = cur[part];
|
|
}
|
|
return cur || fallback;
|
|
}
|
|
|
|
function extractCurrentTheme(themeName) {
|
|
var name = themeName || "Extracted Theme";
|
|
var dark = {};
|
|
var light = {};
|
|
|
|
if (currentTheme === dynamic) {
|
|
dark = buildExtractedDynamicMode("dark", name + " Dark");
|
|
light = buildExtractedDynamicMode("light", name + " Light");
|
|
} else if (currentTheme === custom && customThemeRawData) {
|
|
var rawDark = customThemeRawData.dark || null;
|
|
var rawLight = customThemeRawData.light || null;
|
|
if (rawDark) {
|
|
dark = JSON.parse(JSON.stringify(rawDark));
|
|
if (!dark.name)
|
|
dark.name = name + " Dark";
|
|
} else if (rawLight) {
|
|
dark = buildExtractedDynamicMode("dark", name + " Dark");
|
|
} else {
|
|
dark = currentThemeData ? JSON.parse(JSON.stringify(currentThemeData)) : {};
|
|
dark.name = name + " Dark";
|
|
}
|
|
if (rawLight) {
|
|
light = JSON.parse(JSON.stringify(rawLight));
|
|
if (!light.name)
|
|
light.name = name + " Light";
|
|
} else if (rawDark) {
|
|
light = buildExtractedDynamicMode("light", name + " Light");
|
|
} else {
|
|
light = currentThemeData ? JSON.parse(JSON.stringify(currentThemeData)) : {};
|
|
light.name = name + " Light";
|
|
}
|
|
} else {
|
|
var darkTheme = StockThemes.getThemeByName(currentTheme, false);
|
|
var lightTheme = StockThemes.getThemeByName(currentTheme, true);
|
|
dark = darkTheme ? JSON.parse(JSON.stringify(darkTheme)) : {};
|
|
light = lightTheme ? JSON.parse(JSON.stringify(lightTheme)) : {};
|
|
dark.name = name + " Dark";
|
|
light.name = name + " Light";
|
|
}
|
|
|
|
return JSON.stringify({
|
|
dark: dark,
|
|
light: light
|
|
}, null, 2);
|
|
}
|
|
|
|
function buildExtractedDynamicMode(colorMode, name) {
|
|
return {
|
|
"name": name,
|
|
"primary": getMatugenColorForMode(colorMode, "primary", "#42a5f5"),
|
|
"primaryText": getMatugenColorForMode(colorMode, "on_primary", "#ffffff"),
|
|
"primaryContainer": getMatugenColorForMode(colorMode, "primary_container", "#1976d2"),
|
|
"secondary": getMatugenColorForMode(colorMode, "secondary", "#8ab4f8"),
|
|
"secondaryContainer": getMatugenColorForMode(colorMode, "secondary_container", getMatugenColorForMode(colorMode, "surface_container_high", "#292b2f")),
|
|
"tertiary": getMatugenColorForMode(colorMode, "tertiary", "#efb8c8"),
|
|
"tertiaryContainer": getMatugenColorForMode(colorMode, "tertiary_container", getMatugenColorForMode(colorMode, "surface_container_high", "#292b2f")),
|
|
"surface": getMatugenColorForMode(colorMode, "surface", "#1a1c1e"),
|
|
"surfaceText": getMatugenColorForMode(colorMode, "on_background", "#e3e8ef"),
|
|
"surfaceVariant": getMatugenColorForMode(colorMode, "surface_variant", "#44464f"),
|
|
"surfaceVariantText": getMatugenColorForMode(colorMode, "on_surface_variant", "#c4c7c5"),
|
|
"surfaceTint": getMatugenColorForMode(colorMode, "surface_tint", "#8ab4f8"),
|
|
"background": getMatugenColorForMode(colorMode, "background", "#1a1c1e"),
|
|
"backgroundText": getMatugenColorForMode(colorMode, "on_background", "#e3e8ef"),
|
|
"outline": getMatugenColorForMode(colorMode, "outline", "#8e918f"),
|
|
"surfaceContainerLowest": getMatugenColorForMode(colorMode, "surface_container_lowest", "#0e1013"),
|
|
"surfaceContainerLow": getMatugenColorForMode(colorMode, "surface_container_low", "#181a1d"),
|
|
"surfaceContainer": getMatugenColorForMode(colorMode, "surface_container", "#1e2023"),
|
|
"surfaceContainerHigh": getMatugenColorForMode(colorMode, "surface_container_high", "#292b2f"),
|
|
"surfaceContainerHighest": getMatugenColorForMode(colorMode, "surface_container_highest", "#343740"),
|
|
"error": getMatugenColorForMode(colorMode, "error", "#F2B8B5"),
|
|
"errorText": getMatugenColorForMode(colorMode, "on_error"),
|
|
"errorContainer": getMatugenColorForMode(colorMode, "error_container"),
|
|
"errorContainerText": getMatugenColorForMode(colorMode, "on_error_container"),
|
|
"warning": "#FF9800",
|
|
"info": "#2196F3",
|
|
"success": "#4CAF50"
|
|
};
|
|
}
|
|
|
|
readonly property var currentThemeData: {
|
|
if (currentTheme === "custom") {
|
|
return customThemeData || StockThemes.getThemeByName("purple", isLightMode);
|
|
} else if (currentTheme === dynamic) {
|
|
return buildExtractedDynamicMode(isLightMode ? "light" : "dark", "Dynamic");
|
|
} else {
|
|
return StockThemes.getThemeByName(currentTheme, isLightMode);
|
|
}
|
|
}
|
|
|
|
readonly property var availableMatugenSchemes: {
|
|
const schemes = _matugenSchemeDefs;
|
|
const seen = {};
|
|
for (let i = 0; i < schemes.length; i++) {
|
|
const label = schemes[i].label;
|
|
if (seen[label] === undefined) {
|
|
seen[label] = true;
|
|
continue;
|
|
}
|
|
// duplicate translations otherwise collapse the label-keyed dropdown onto one scheme (#3154)
|
|
schemes[i].label = label + " (" + schemes[i].value.replace("scheme-", "") + ")";
|
|
}
|
|
return schemes;
|
|
}
|
|
|
|
readonly property var _matugenSchemeDefs: [({
|
|
"value": "scheme-tonal-spot",
|
|
"label": I18n.tr("Tonal Spot", "matugen color scheme option"),
|
|
"description": I18n.tr("Balanced palette with focused accents (default).")
|
|
}), ({
|
|
"value": "scheme-vibrant",
|
|
"label": I18n.tr("Vibrant", "matugen color scheme option"),
|
|
"description": I18n.tr("Lively palette with saturated accents.")
|
|
}), ({
|
|
"value": "scheme-content",
|
|
"label": I18n.tr("Content", "matugen color scheme option"),
|
|
"description": I18n.tr("Derives colors that closely match the underlying image.")
|
|
}), ({
|
|
"value": "scheme-expressive",
|
|
"label": I18n.tr("Expressive", "matugen color scheme option"),
|
|
"description": I18n.tr("Vibrant palette with playful saturation.")
|
|
}), ({
|
|
"value": "scheme-fidelity",
|
|
"label": I18n.tr("Fidelity", "matugen color scheme option"),
|
|
"description": I18n.tr("High-fidelity palette that preserves source hues.")
|
|
}), ({
|
|
"value": "scheme-fruit-salad",
|
|
"label": I18n.tr("Fruit Salad", "matugen color scheme option"),
|
|
"description": I18n.tr("Colorful mix of bright contrasting accents.")
|
|
}), ({
|
|
"value": "scheme-monochrome",
|
|
"label": I18n.tr("Monochrome", "matugen color scheme option"),
|
|
"description": I18n.tr("Minimal palette built around a single hue.")
|
|
}), ({
|
|
"value": "scheme-neutral",
|
|
"label": I18n.tr("Neutral", "matugen color scheme option"),
|
|
"description": I18n.tr("Muted palette with subdued, calming tones.")
|
|
}), ({
|
|
"value": "scheme-rainbow",
|
|
"label": I18n.tr("Rainbow", "matugen color scheme option"),
|
|
"description": I18n.tr("Diverse palette spanning the full spectrum.")
|
|
}), ({
|
|
"value": "scheme-smart",
|
|
"label": I18n.tr("Smart", "matugen color scheme option"),
|
|
"description": I18n.tr("Automatically picks the scheme variant based on the wallpaper.")
|
|
})]
|
|
|
|
function getMatugenScheme(value) {
|
|
const schemes = availableMatugenSchemes;
|
|
for (var i = 0; i < schemes.length; i++) {
|
|
if (schemes[i].value === value)
|
|
return schemes[i];
|
|
}
|
|
return schemes[0];
|
|
}
|
|
|
|
readonly property var availableSourceModes: [({
|
|
"value": "dominant",
|
|
"label": I18n.tr("Dominant", "matugen source color option")
|
|
}), ({
|
|
"value": "colorful",
|
|
"label": I18n.tr("Colorful", "matugen source color option")
|
|
}), ({
|
|
"value": "darkness",
|
|
"label": I18n.tr("Darkest", "matugen source color option")
|
|
}), ({
|
|
"value": "lightness",
|
|
"label": I18n.tr("Lightest", "matugen source color option")
|
|
}), ({
|
|
"value": "saturation",
|
|
"label": I18n.tr("Most Saturated", "matugen source color option")
|
|
}), ({
|
|
"value": "less-saturation",
|
|
"label": I18n.tr("Least Saturated", "matugen source color option")
|
|
}), ({
|
|
"value": "value",
|
|
"label": I18n.tr("Most Vivid", "matugen source color option")
|
|
})]
|
|
|
|
function getSourceMode(value) {
|
|
const modes = availableSourceModes;
|
|
for (var i = 0; i < modes.length; i++) {
|
|
if (modes[i].value === value)
|
|
return modes[i];
|
|
}
|
|
return modes[0];
|
|
}
|
|
|
|
property color primary: currentThemeData.primary
|
|
property color primaryText: currentThemeData.primaryText
|
|
property color secondary: currentThemeData.secondary
|
|
property color tertiary: currentThemeData.tertiary || currentThemeData.secondary
|
|
property color surface: currentThemeData.surface
|
|
property color surfaceText: currentThemeData.surfaceText
|
|
property color surfaceVariant: currentThemeData.surfaceVariant
|
|
property color surfaceVariantText: currentThemeData.surfaceVariantText
|
|
property color surfaceTint: currentThemeData.surfaceTint
|
|
property color background: currentThemeData.background
|
|
property color backgroundText: currentThemeData.backgroundText
|
|
property color outline: currentThemeData.outline
|
|
property color outlineVariant: currentThemeData.outlineVariant || withAlpha(outline, 0.6)
|
|
property color surfaceContainerLowest: currentThemeData.surfaceContainerLowest || blend(surfaceContainer, surface, 1.2)
|
|
property color surfaceContainerLow: currentThemeData.surfaceContainerLow || blend(surface, surfaceContainer, 0.667)
|
|
property color surfaceContainer: currentThemeData.surfaceContainer
|
|
property color surfaceContainerHigh: currentThemeData.surfaceContainerHigh
|
|
property color surfaceContainerHighest: currentThemeData.surfaceContainerHighest || surfaceContainerHigh
|
|
property color surfaceBright: currentThemeData.surfaceBright || (isLightMode ? surface : surfaceContainerHighest)
|
|
property color surfaceDim: currentThemeData.surfaceDim || (isLightMode ? surfaceContainer : background)
|
|
property color primaryContainer: currentThemeData.primaryContainer || blend(surfaceContainerHigh, primary, 0.45)
|
|
property color secondaryContainer: currentThemeData.secondaryContainer || blend(surfaceContainerHigh, secondary, 0.35)
|
|
property color tertiaryContainer: currentThemeData.tertiaryContainer || blend(surfaceContainerHigh, tertiary, 0.35)
|
|
property color inverseSurface: currentThemeData.inverseSurface || surfaceText
|
|
property color inverseOnSurface: currentThemeData.inverseOnSurface || surface
|
|
|
|
// on<Role> next to a <role> property parses as a signal handler; only Binding elements assign them.
|
|
property color onSurface
|
|
property color onSurfaceVariant
|
|
property color onPrimary
|
|
property color onPrimaryContainer
|
|
property color onSecondaryContainer
|
|
property color onError
|
|
property color onErrorContainer
|
|
property color onTertiaryContainer
|
|
property color onSurface_12: withAlpha(onSurface, 0.12)
|
|
property color onSurface_38: withAlpha(onSurface, 0.38)
|
|
property color onSurfaceVariant_30: withAlpha(onSurfaceVariant, 0.30)
|
|
property color onSurfaceVariant_40
|
|
readonly property list<QtObject> roleBindings: [
|
|
Binding {
|
|
target: root
|
|
property: "onSurfaceVariant_40"
|
|
value: root.withAlpha(root.onSurfaceVariant, 0.4)
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onError"
|
|
value: root.currentThemeData.errorText || root.getMatugenColor("on_error", root.surface)
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onErrorContainer"
|
|
value: root.currentThemeData.errorContainerText || root.getMatugenColor("on_error_container", root.onSurface)
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onSurface"
|
|
value: root.surfaceText
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onSurfaceVariant"
|
|
value: root.surfaceVariantText
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onPrimary"
|
|
value: root.primaryText
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onPrimaryContainer"
|
|
value: root.currentThemeData.onPrimaryContainer || root.surfaceText
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onSecondaryContainer"
|
|
value: root.currentThemeData.onSecondaryContainer || root.surfaceText
|
|
},
|
|
Binding {
|
|
target: root
|
|
property: "onTertiaryContainer"
|
|
value: root.currentThemeData.onTertiaryContainer || root.surfaceText
|
|
}
|
|
]
|
|
readonly property real tonalTintAlpha: 0.16
|
|
|
|
property color error: currentThemeData.error || "#F2B8B5"
|
|
property color errorContainer: currentThemeData.errorContainer || getMatugenColor("error_container", surfaceContainerHigh)
|
|
property color warning: currentThemeData.warning || "#FF9800"
|
|
property color info: currentThemeData.info || "#2196F3"
|
|
property color tempWarning: "#ff9933"
|
|
property color tempDanger: "#ff5555"
|
|
property color success: currentThemeData.success || "#4CAF50"
|
|
|
|
property color primaryHover: withAlpha(primary, 0.12)
|
|
property color primaryHoverLight: withAlpha(primary, transparentBlurLayers ? 0.12 : 0.08)
|
|
property color primaryPressed: withAlpha(primary, transparentBlurLayers ? 0.24 : 0.16)
|
|
property color primarySelected: withAlpha(primary, 0.3)
|
|
property color primaryBackground: withAlpha(primary, 0.04)
|
|
|
|
property color secondaryHover: withAlpha(secondary, 0.08)
|
|
|
|
property color surfaceHover: withAlpha(surfaceVariant, 0.08)
|
|
property color surfacePressed: withAlpha(surfaceVariant, 0.12)
|
|
property color surfaceSelected: withAlpha(surfaceVariant, 0.15)
|
|
property color surfaceLight: withAlpha(surfaceVariant, transparentBlurLayers ? 0.3 : 0.1)
|
|
property color surfaceVariantAlpha: withAlpha(surfaceVariant, 0.2)
|
|
|
|
readonly property bool foregroundLayers: typeof SettingsData === "undefined" || (SettingsData.blurForegroundLayers ?? true)
|
|
readonly property bool blurForegroundLayers: blurLayersActive && foregroundLayers
|
|
readonly property bool transparentBlurLayers: blurLayersActive && !foregroundLayers
|
|
readonly property real foregroundLayerTransparency: typeof SettingsData === "undefined" ? 1.0 : (SettingsData.foregroundLayerTransparency ?? 1.0)
|
|
readonly property bool notificationForegroundLayers: typeof SettingsData === "undefined" || (SettingsData.notificationForegroundLayers ?? true)
|
|
readonly property color readableSurface: withAlpha(surfaceContainer, popupTransparency)
|
|
readonly property color readableSurfaceHigh: withAlpha(surfaceContainerHigh, popupTransparency)
|
|
readonly property color floatingSurface: readableSurface
|
|
readonly property color floatingSurfaceHigh: foregroundColor(surfaceContainerHigh)
|
|
readonly property bool floatingWindowSynced: typeof SettingsData === "undefined" || (SettingsData.floatingWindowSyncGlobal ?? true)
|
|
readonly property real floatingWindowTransparency: {
|
|
if (typeof SettingsData === "undefined" || floatingWindowSynced)
|
|
return popupTransparency;
|
|
return SettingsData.floatingWindowTransparency ?? 1.0;
|
|
}
|
|
readonly property bool floatingWindowForegroundLayers: floatingWindowSynced ? foregroundLayers : (SettingsData.floatingWindowForegroundLayers ?? true)
|
|
readonly property real floatingWindowForegroundTransparency: {
|
|
if (typeof SettingsData === "undefined" || floatingWindowSynced)
|
|
return foregroundLayerTransparency;
|
|
return SettingsData.floatingWindowForegroundTransparency ?? 1.0;
|
|
}
|
|
readonly property real foregroundAlpha: Surface.foregroundAlpha(foregroundLayers, foregroundLayerTransparency)
|
|
readonly property real floatingWindowForegroundAlpha: Surface.foregroundAlpha(floatingWindowForegroundLayers, floatingWindowForegroundTransparency)
|
|
|
|
function isFloatingWindow(item) {
|
|
return Surface.isFloatingWindow(item);
|
|
}
|
|
|
|
function foregroundColor(baseColor, floatingWindow = false) {
|
|
return blendAlpha(baseColor, floatingWindow ? floatingWindowForegroundAlpha : foregroundAlpha);
|
|
}
|
|
|
|
readonly property color floatingWindowSurface: withAlpha(surfaceContainer, floatingWindowTransparency)
|
|
readonly property color floatingWindowSurfaceHigh: foregroundColor(surfaceContainerHigh, true)
|
|
readonly property color floatingWindowNestedSurface: floatingWindowSurfaceHigh
|
|
readonly property color notepadWindowSurface: withAlpha(surfaceContainer, notepadTransparency)
|
|
readonly property color nestedSurface: floatingSurfaceHigh
|
|
readonly property color notificationFloatingSurface: notificationForegroundLayers ? readableSurface : withAlpha(readableSurface, 0)
|
|
readonly property color notificationFloatingSurfaceHigh: notificationForegroundLayers ? readableSurfaceHigh : withAlpha(readableSurfaceHigh, 0)
|
|
readonly property color notificationNestedSurface: notificationFloatingSurfaceHigh
|
|
readonly property real blurLayerOutlineOpacity: Math.max(0, Math.min(1, typeof SettingsData === "undefined" ? 0.12 : (SettingsData.blurLayerOutlineOpacity ?? 0.12)))
|
|
readonly property real layerOutlineOpacity: blurLayerOutlineOpacity
|
|
readonly property int layerOutlineWidth: layerOutlineOpacity > 0 ? 1 : 0
|
|
readonly property real floatingWindowFieldAlpha: floatingWindowForegroundAlpha
|
|
readonly property color floatingWindowFieldColor: withAlpha(surfaceContainerHigh, floatingWindowFieldAlpha)
|
|
readonly property real popupFieldAlpha: foregroundAlpha
|
|
readonly property color popupFieldColor: withAlpha(surfaceContainerHigh, popupFieldAlpha)
|
|
readonly property color popupFieldBorderColor: withAlpha(outline, blurLayersActive ? 0.16 : layerOutlineOpacity)
|
|
readonly property color popupFieldFocusedBorderColor: withAlpha(primary, blurLayersActive ? 0.72 : 1.0)
|
|
readonly property color floatingWindowFieldBorderColor: popupFieldBorderColor
|
|
readonly property color floatingWindowFieldFocusedBorderColor: popupFieldFocusedBorderColor
|
|
property color surfaceTextHover: withAlpha(surfaceText, 0.08)
|
|
property color surfaceTextAlpha: withAlpha(surfaceText, 0.3)
|
|
|
|
function roleColor(mode) {
|
|
switch (mode) {
|
|
case "primary":
|
|
case "pri":
|
|
return primary;
|
|
case "primaryContainer":
|
|
return primaryContainer;
|
|
case "secondary":
|
|
case "sec":
|
|
return secondary;
|
|
case "secondaryContainer":
|
|
return secondaryContainer;
|
|
case "tertiary":
|
|
case "ter":
|
|
return tertiary;
|
|
case "tertiaryContainer":
|
|
return tertiaryContainer;
|
|
case "surfaceText":
|
|
return surfaceText;
|
|
case "surfaceVariant":
|
|
return surfaceVariant;
|
|
case "s":
|
|
return surface;
|
|
case "scll":
|
|
return surfaceContainerLowest;
|
|
case "scl":
|
|
return surfaceContainerLow;
|
|
case "sc":
|
|
return surfaceContainer;
|
|
case "sch":
|
|
return surfaceContainerHigh;
|
|
case "schh":
|
|
return surfaceContainerHighest;
|
|
case "sth":
|
|
return surfaceTextHover;
|
|
case "error":
|
|
case "err":
|
|
return error;
|
|
default:
|
|
return withAlpha(surface, 0);
|
|
}
|
|
}
|
|
property color surfaceTextLight: withAlpha(surfaceText, 0.06)
|
|
property color surfaceTextSecondary: withAlpha(surfaceText, 0.6)
|
|
property color surfaceTextMedium: withAlpha(surfaceText, 0.7)
|
|
|
|
property color outlineButton: withAlpha(outline, 0.5)
|
|
property color outlineLight: withAlpha(outline, Math.min(1, layerOutlineOpacity * 0.625))
|
|
property color outlineMedium: withAlpha(outline, layerOutlineOpacity)
|
|
property color outlineStrong: withAlpha(outline, Math.min(1, layerOutlineOpacity * 1.5))
|
|
property color outlineHeavy: withAlpha(outline, 0.2)
|
|
|
|
property color errorHover: withAlpha(error, 0.12)
|
|
property color errorPressed: withAlpha(error, 0.16)
|
|
property color errorSelected: withAlpha(error, 0.3)
|
|
property color warningHover: withAlpha(warning, 0.12)
|
|
|
|
readonly property color ccTileActiveBg: {
|
|
switch (SettingsData.controlCenterTileColorMode) {
|
|
case "primaryContainer":
|
|
return primaryContainer;
|
|
case "secondary":
|
|
return secondary;
|
|
case "surfaceVariant":
|
|
return surfaceVariant;
|
|
default:
|
|
return primary;
|
|
}
|
|
}
|
|
|
|
readonly property color ccPillInactiveBg: transparentBlurLayers ? withAlpha(surfaceContainerHigh, 0.08) : nestedSurface
|
|
|
|
readonly property color ccTileActiveText: {
|
|
switch (SettingsData.controlCenterTileColorMode) {
|
|
case "primaryContainer":
|
|
return onPrimaryContainer;
|
|
case "secondary":
|
|
return surfaceText;
|
|
case "surfaceVariant":
|
|
return surfaceText;
|
|
default:
|
|
return primaryText;
|
|
}
|
|
}
|
|
|
|
readonly property color buttonBg: {
|
|
switch (SettingsData.buttonColorMode) {
|
|
case "primaryContainer":
|
|
return primaryContainer;
|
|
case "secondary":
|
|
return secondary;
|
|
case "surfaceVariant":
|
|
return surfaceVariant;
|
|
default:
|
|
return primary;
|
|
}
|
|
}
|
|
|
|
readonly property color buttonText: {
|
|
switch (SettingsData.buttonColorMode) {
|
|
case "primaryContainer":
|
|
return primary;
|
|
case "secondary":
|
|
return surfaceText;
|
|
case "surfaceVariant":
|
|
return surfaceText;
|
|
default:
|
|
return primaryText;
|
|
}
|
|
}
|
|
|
|
readonly property color buttonHover: {
|
|
switch (SettingsData.buttonColorMode) {
|
|
case "primaryContainer":
|
|
return withAlpha(primary, 0.12);
|
|
case "secondary":
|
|
return withAlpha(surfaceText, 0.12);
|
|
case "surfaceVariant":
|
|
return withAlpha(surfaceText, 0.12);
|
|
default:
|
|
return primaryHover;
|
|
}
|
|
}
|
|
|
|
readonly property color buttonPressed: {
|
|
switch (SettingsData.buttonColorMode) {
|
|
case "primaryContainer":
|
|
return withAlpha(primary, 0.16);
|
|
case "secondary":
|
|
return withAlpha(surfaceText, 0.16);
|
|
case "surfaceVariant":
|
|
return withAlpha(surfaceText, 0.16);
|
|
default:
|
|
return primaryPressed;
|
|
}
|
|
}
|
|
|
|
property color shadowMedium: Qt.rgba(0, 0, 0, 0.08)
|
|
property color shadowStrong: Qt.rgba(0, 0, 0, 0.3)
|
|
|
|
readonly property bool elevationEnabled: typeof SettingsData !== "undefined" && (SettingsData.m3ElevationEnabled ?? true)
|
|
readonly property real elevationBlurMax: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? Math.min(128, Math.max(32, SettingsData.m3ElevationIntensity * 2)) : 64
|
|
|
|
readonly property real _elevMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? SettingsData.m3ElevationIntensity / 12 : 1
|
|
readonly property real _opMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationOpacity !== undefined ? SettingsData.m3ElevationOpacity / 60 : 1
|
|
function normalizeElevationDirection(direction) {
|
|
switch (direction) {
|
|
case "top":
|
|
case "topLeft":
|
|
case "topRight":
|
|
case "bottom":
|
|
case "bottomLeft":
|
|
case "bottomRight":
|
|
case "left":
|
|
case "right":
|
|
case "autoBar":
|
|
return direction;
|
|
default:
|
|
return "top";
|
|
}
|
|
}
|
|
|
|
readonly property string elevationLightDirection: {
|
|
if (typeof SettingsData === "undefined" || !SettingsData.m3ElevationLightDirection)
|
|
return "top";
|
|
switch (SettingsData.m3ElevationLightDirection) {
|
|
case "autoBar":
|
|
case "top":
|
|
case "topLeft":
|
|
case "topRight":
|
|
case "bottom":
|
|
return SettingsData.m3ElevationLightDirection;
|
|
default:
|
|
return "top";
|
|
}
|
|
}
|
|
readonly property real _elevDiagRatio: 0.55
|
|
readonly property string _globalElevationDirForTokens: {
|
|
const normalized = normalizeElevationDirection(elevationLightDirection);
|
|
return normalized === "autoBar" ? "top" : normalized;
|
|
}
|
|
readonly property real _elevDirX: {
|
|
switch (_globalElevationDirForTokens) {
|
|
case "topLeft":
|
|
case "bottomLeft":
|
|
case "left":
|
|
return 1;
|
|
case "topRight":
|
|
case "bottomRight":
|
|
case "right":
|
|
return -1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
readonly property real _elevDirY: {
|
|
switch (_globalElevationDirForTokens) {
|
|
case "bottom":
|
|
case "bottomLeft":
|
|
case "bottomRight":
|
|
return -1;
|
|
case "left":
|
|
case "right":
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
readonly property real _elevDirXScale: (_globalElevationDirForTokens === "left" || _globalElevationDirForTokens === "right") ? 1 : _elevDiagRatio
|
|
|
|
readonly property var elevationLevel1: ({
|
|
blurPx: 4 * _elevMult,
|
|
offsetX: 1 * _elevMult * _elevDirXScale * _elevDirX,
|
|
offsetY: 1 * _elevMult * _elevDirY,
|
|
spreadPx: 0,
|
|
alpha: 0.2 * _opMult
|
|
})
|
|
readonly property var elevationLevel2: ({
|
|
blurPx: 8 * _elevMult,
|
|
offsetX: 4 * _elevMult * _elevDirXScale * _elevDirX,
|
|
offsetY: 4 * _elevMult * _elevDirY,
|
|
spreadPx: 0,
|
|
alpha: 0.25 * _opMult
|
|
})
|
|
readonly property var elevationLevel3: ({
|
|
blurPx: 12 * _elevMult,
|
|
offsetX: 6 * _elevMult * _elevDirXScale * _elevDirX,
|
|
offsetY: 6 * _elevMult * _elevDirY,
|
|
spreadPx: 0,
|
|
alpha: 0.3 * _opMult
|
|
})
|
|
readonly property var elevationLevel4: ({
|
|
blurPx: 16 * _elevMult,
|
|
offsetX: 8 * _elevMult * _elevDirXScale * _elevDirX,
|
|
offsetY: 8 * _elevMult * _elevDirY,
|
|
spreadPx: 0,
|
|
alpha: 0.3 * _opMult
|
|
})
|
|
readonly property var elevationLevel5: ({
|
|
blurPx: 20 * _elevMult,
|
|
offsetX: 10 * _elevMult * _elevDirXScale * _elevDirX,
|
|
offsetY: 10 * _elevMult * _elevDirY,
|
|
spreadPx: 0,
|
|
alpha: 0.3 * _opMult
|
|
})
|
|
|
|
function elevationOffsetMagnitude(level, fallback, direction) {
|
|
if (!level) {
|
|
return fallback !== undefined ? Math.abs(fallback) : 0;
|
|
}
|
|
const yMag = Math.abs(level.offsetY !== undefined ? level.offsetY : 0);
|
|
if (yMag > 0)
|
|
return yMag;
|
|
const xMag = Math.abs(level.offsetX !== undefined ? level.offsetX : 0);
|
|
if (xMag > 0) {
|
|
if (direction === "left" || direction === "right")
|
|
return xMag;
|
|
return xMag / _elevDiagRatio;
|
|
}
|
|
return fallback !== undefined ? Math.abs(fallback) : 0;
|
|
}
|
|
|
|
function elevationOffsetXFor(level, direction, fallback) {
|
|
const dir = normalizeElevationDirection(direction || elevationLightDirection);
|
|
const mag = elevationOffsetMagnitude(level, fallback, dir);
|
|
switch (dir) {
|
|
case "topLeft":
|
|
case "bottomLeft":
|
|
return mag * _elevDiagRatio;
|
|
case "topRight":
|
|
case "bottomRight":
|
|
return -mag * _elevDiagRatio;
|
|
case "left":
|
|
return mag;
|
|
case "right":
|
|
return -mag;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function elevationOffsetYFor(level, direction, fallback) {
|
|
const dir = normalizeElevationDirection(direction || elevationLightDirection);
|
|
const mag = elevationOffsetMagnitude(level, fallback, dir);
|
|
switch (dir) {
|
|
case "bottom":
|
|
case "bottomLeft":
|
|
case "bottomRight":
|
|
return -mag;
|
|
case "left":
|
|
case "right":
|
|
return 0;
|
|
default:
|
|
return mag;
|
|
}
|
|
}
|
|
|
|
function elevationOffsetX(level, fallback) {
|
|
return elevationOffsetXFor(level, elevationLightDirection, fallback);
|
|
}
|
|
|
|
function elevationOffsetY(level, fallback) {
|
|
return elevationOffsetYFor(level, elevationLightDirection, fallback);
|
|
}
|
|
|
|
function elevationRenderPadding(level, direction, fallbackOffset, extraPadding, minPadding) {
|
|
const dir = direction !== undefined ? direction : elevationLightDirection;
|
|
const blur = (level && level.blurPx !== undefined) ? Math.max(0, level.blurPx) : 0;
|
|
const spread = (level && level.spreadPx !== undefined) ? Math.max(0, level.spreadPx) : 0;
|
|
const fallback = fallbackOffset !== undefined ? fallbackOffset : 0;
|
|
const extra = extraPadding !== undefined ? extraPadding : 8;
|
|
const minPad = minPadding !== undefined ? minPadding : 16;
|
|
const offsetX = Math.abs(elevationOffsetXFor(level, dir, fallback));
|
|
const offsetY = Math.abs(elevationOffsetYFor(level, dir, fallback));
|
|
return Math.max(minPad, blur + spread + Math.max(offsetX, offsetY) + extra);
|
|
}
|
|
|
|
function elevationShadowColor(level) {
|
|
const alpha = (level && level.alpha !== undefined) ? level.alpha : 0.3;
|
|
let r = 0;
|
|
let g = 0;
|
|
let b = 0;
|
|
|
|
if (typeof SettingsData !== "undefined") {
|
|
const mode = SettingsData.m3ElevationColorMode || "default";
|
|
if (mode === "default") {
|
|
r = 0;
|
|
g = 0;
|
|
b = 0;
|
|
} else if (mode === "text") {
|
|
r = surfaceText.r;
|
|
g = surfaceText.g;
|
|
b = surfaceText.b;
|
|
} else if (mode === "primary") {
|
|
r = primary.r;
|
|
g = primary.g;
|
|
b = primary.b;
|
|
} else if (mode === "surfaceVariant") {
|
|
r = surfaceVariant.r;
|
|
g = surfaceVariant.g;
|
|
b = surfaceVariant.b;
|
|
} else if (mode === "custom" && SettingsData.m3ElevationCustomColor) {
|
|
const c = Qt.color(SettingsData.m3ElevationCustomColor);
|
|
r = c.r;
|
|
g = c.g;
|
|
b = c.b;
|
|
}
|
|
}
|
|
return Qt.rgba(r, g, b, alpha);
|
|
}
|
|
function elevationAmbient(level) {
|
|
const blur = (level && level.blurPx !== undefined) ? Math.max(0, level.blurPx) : 0;
|
|
const alpha = ((level && level.alpha !== undefined) ? level.alpha : 0.3) * 0.5;
|
|
return {
|
|
blurPx: blur * 1.75,
|
|
spreadPx: 1,
|
|
alpha: alpha
|
|
};
|
|
}
|
|
|
|
readonly property int currentAnimationBaseDuration: typeof SettingsData !== "undefined" ? SettingsData.animationDuration : 250
|
|
readonly property int currentAnimationSpeed: currentAnimationBaseDuration > 0 ? SettingsData.AnimationSpeed.Custom : SettingsData.AnimationSpeed.None
|
|
|
|
readonly property int shorterDuration: Math.round(currentAnimationBaseDuration * 0.2)
|
|
readonly property int shortDuration: Math.round(currentAnimationBaseDuration * 0.3)
|
|
readonly property bool snapListModelChanges: shortDuration <= 0
|
|
readonly property int mediumDuration: Math.round(currentAnimationBaseDuration * 0.6)
|
|
readonly property int longDuration: currentAnimationBaseDuration
|
|
readonly property int extraLongDuration: currentAnimationBaseDuration * 2
|
|
readonly property int standardEasing: Easing.OutCubic
|
|
readonly property int emphasizedEasing: Easing.OutQuart
|
|
|
|
readonly property var expressiveCurves: {
|
|
"emphasized": [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1],
|
|
"emphasizedAccel": [0.3, 0, 0.8, 0.15, 1, 1],
|
|
"emphasizedDecel": [0.05, 0.7, 0.1, 1, 1, 1],
|
|
"standard": [0.2, 0, 0, 1, 1, 1],
|
|
"standardAccel": [0.3, 0, 1, 1, 1, 1],
|
|
"standardDecel": [0, 0, 0, 1, 1, 1],
|
|
"expressiveFastSpatial": [0.42, 1.67, 0.21, 0.9, 1, 1],
|
|
"expressiveDefaultSpatial": [0.38, 1.21, 0.22, 1, 1, 1],
|
|
"expressiveEffects": [0.34, 0.8, 0.34, 1, 1, 1]
|
|
}
|
|
|
|
// Theme is the canonical access point for animation variant state. The
|
|
// aliases below forward to AnimVariants.qml so consumers don't need two
|
|
// imports. ~200 call sites read through Theme.variantEnterCurve /
|
|
// Theme.isConnectedEffect / etc. — do NOT migrate to AnimVariants directly.
|
|
readonly property list<real> variantEnterCurve: AnimVariants.variantEnterCurve
|
|
readonly property list<real> variantExitCurve: AnimVariants.variantExitCurve
|
|
readonly property list<real> variantModalEnterCurve: AnimVariants.variantModalEnterCurve
|
|
readonly property list<real> variantModalExitCurve: AnimVariants.variantModalExitCurve
|
|
readonly property list<real> variantPopoutEnterCurve: AnimVariants.variantPopoutEnterCurve
|
|
readonly property list<real> variantPopoutExitCurve: AnimVariants.variantPopoutExitCurve
|
|
readonly property list<real> variantPopoutResizeCurve: AnimVariants.variantPopoutResizeCurve
|
|
readonly property real variantEnterDurationFactor: AnimVariants.variantEnterDurationFactor
|
|
readonly property real variantExitDurationFactor: AnimVariants.variantExitDurationFactor
|
|
readonly property real variantOpacityDurationScale: AnimVariants.variantOpacityDurationScale
|
|
readonly property bool isDirectionalEffect: AnimVariants.isDirectionalEffect
|
|
readonly property bool isFluidEffect: AnimVariants.isFluidEffect
|
|
readonly property bool isDepthEffect: AnimVariants.isDepthEffect
|
|
readonly property bool isConnectedEffect: AnimVariants.isConnectedEffect
|
|
readonly property real connectedCornerRadius: {
|
|
if (typeof SettingsData === "undefined")
|
|
return 12;
|
|
return FrameTransitionState.effectiveConnectedFrameModeActive ? SettingsData.frameRounding : windowRadius;
|
|
}
|
|
readonly property color connectedSurfaceColor: {
|
|
if (typeof SettingsData === "undefined")
|
|
return withAlpha(surfaceContainer, popupTransparency);
|
|
return isConnectedEffect ? withAlpha(SettingsData.effectiveFrameColor, SettingsData.frameOpacity) : withAlpha(surfaceContainer, popupTransparency);
|
|
}
|
|
readonly property real connectedSurfaceRadius: isConnectedEffect ? connectedCornerRadius : windowRadius
|
|
readonly property bool connectedSurfaceBlurEnabled: (typeof SettingsData === "undefined") ? true : (!isConnectedEffect || SettingsData.frameBlurEnabled)
|
|
readonly property real effectScaleCollapsed: AnimVariants.effectScaleCollapsed
|
|
readonly property real effectAnimOffset: AnimVariants.effectAnimOffset
|
|
function variantDuration(baseDuration, entering) {
|
|
return AnimVariants.variantDuration(baseDuration, entering);
|
|
}
|
|
function variantExitCleanupPadding() {
|
|
return AnimVariants.variantExitCleanupPadding();
|
|
}
|
|
function variantCloseInterval(baseDuration) {
|
|
return AnimVariants.variantCloseInterval(baseDuration);
|
|
}
|
|
|
|
readonly property var expressiveDurations: {
|
|
if (typeof SettingsData === "undefined") {
|
|
return {
|
|
"fast": 200,
|
|
"normal": 400,
|
|
"large": 600,
|
|
"extraLarge": 1000,
|
|
"expressiveFastSpatial": 350,
|
|
"expressiveDefaultSpatial": 500,
|
|
"expressiveEffects": 200
|
|
};
|
|
}
|
|
|
|
const baseDuration = currentAnimationBaseDuration;
|
|
return {
|
|
"fast": baseDuration * 0.4,
|
|
"normal": baseDuration * 0.8,
|
|
"large": baseDuration * 1.2,
|
|
"extraLarge": baseDuration * 2.0,
|
|
"expressiveFastSpatial": baseDuration * 0.7,
|
|
"expressiveDefaultSpatial": baseDuration,
|
|
"expressiveEffects": baseDuration * 0.4
|
|
};
|
|
}
|
|
|
|
// Expressive spatial spring presets ([stiffness, damping], unit mass) tuned to a
|
|
// 500ms reference transition; runtime values scale via springPreset().
|
|
readonly property real morphSettleEpsilon: 0.02
|
|
readonly property real morphLayerEpsilon: 0.002
|
|
|
|
readonly property var springSpecs: {
|
|
"expressive": [560, 37],
|
|
"fast": [220, 23],
|
|
"default": [300, 24]
|
|
}
|
|
|
|
// Damping multipliers for the user-facing spring bounce setting:
|
|
// crisp settles without overshoot, playful adds visible bounce.
|
|
readonly property var springDampingScales: [1.22, 1.0, 0.82]
|
|
|
|
// Must stay under the 16px shadow motion padding every fluid surface reserves.
|
|
readonly property var fluidOvershootLimits: [0, 4, 10]
|
|
readonly property real fluidOvershootLimit: {
|
|
if (typeof SettingsData === "undefined" || springMotionDisabled)
|
|
return 0;
|
|
return fluidOvershootLimits[Math.round(SettingsData.springBounce)] ?? 4;
|
|
}
|
|
|
|
function tunedSpring(spec, baseDuration) {
|
|
const f = Math.max(0.05, baseDuration / 500);
|
|
const bounce = typeof SettingsData !== "undefined" && SettingsData.springBounce >= 0 && SettingsData.springBounce < springDampingScales.length ? springDampingScales[Math.round(SettingsData.springBounce)] : 1;
|
|
return {
|
|
"stiffness": spec[0] / (f * f),
|
|
"damping": spec[1] / f * bounce,
|
|
"mass": 1
|
|
};
|
|
}
|
|
|
|
function springPreset(name, baseDuration) {
|
|
return tunedSpring(springSpecs[name] ?? springSpecs["default"], baseDuration);
|
|
}
|
|
|
|
readonly property bool springMotionDisabled: currentAnimationBaseDuration <= 0
|
|
|
|
readonly property int notificationAnimationBaseDuration: typeof SettingsData !== "undefined" ? SettingsData.notificationAnimationDuration : 200
|
|
|
|
readonly property int notificationEnterDuration: Math.round(notificationAnimationBaseDuration * 0.875)
|
|
readonly property int notificationExitDuration: Math.round(notificationAnimationBaseDuration * 0.75)
|
|
readonly property int notificationStackShiftDuration: notificationAnimationBaseDuration
|
|
readonly property int notificationStackStaggerDuration: Math.round(notificationAnimationBaseDuration * 0.5)
|
|
|
|
readonly property int notificationExpandDuration: {
|
|
const base = notificationAnimationBaseDuration;
|
|
return base === 0 ? 0 : Math.round(base * 1.0);
|
|
}
|
|
|
|
readonly property int notificationCollapseDuration: {
|
|
const base = notificationAnimationBaseDuration;
|
|
return base === 0 ? 0 : Math.round(base * 0.85);
|
|
}
|
|
|
|
readonly property int notificationInlineExpandDuration: Math.round(notificationAnimationBaseDuration * 0.925)
|
|
readonly property int notificationInlineCollapseDuration: Math.round(notificationAnimationBaseDuration * 0.75)
|
|
|
|
readonly property real notificationExpandedIconSizeNormal: avatarSize
|
|
readonly property real notificationExpandedIconSizeCompact: avatarSize
|
|
readonly property real notificationButtonCornerRadius: cornerRadiusFull
|
|
readonly property real notificationHoverRevealMargin: spacingXL
|
|
readonly property real notificationContentSpacing: spacingXS
|
|
readonly property real notificationCardPadding: spacingM
|
|
readonly property real notificationCardPaddingCompact: spacingS
|
|
|
|
readonly property real stateLayerHover: 0.08
|
|
readonly property real stateLayerFocus: 0.12
|
|
readonly property real stateLayerPressed: 0.12
|
|
readonly property real stateLayerDrag: 0.16
|
|
|
|
readonly property int popoutAnimationDuration: {
|
|
if (typeof SettingsData === "undefined")
|
|
return 150;
|
|
if (SettingsData.syncComponentAnimationSpeeds)
|
|
return Math.min(currentAnimationBaseDuration, 1000);
|
|
return SettingsData.popoutAnimationDuration;
|
|
}
|
|
|
|
readonly property int modalAnimationDuration: {
|
|
if (typeof SettingsData === "undefined")
|
|
return 150;
|
|
if (SettingsData.syncComponentAnimationSpeeds)
|
|
return Math.min(currentAnimationBaseDuration, 1000);
|
|
return SettingsData.modalAnimationDuration;
|
|
}
|
|
|
|
readonly property real radiusStrength: typeof SettingsData !== "undefined" ? SettingsData.radiusStrength : 50
|
|
readonly property real shapeScale: Shape.scaleForStrength(radiusStrength)
|
|
readonly property real cornerRadius: cornerRadiusM
|
|
readonly property real cornerRadiusXXS: Shape.radius("xxs", shapeScale)
|
|
readonly property real cornerRadiusXS: Shape.radius("xs", shapeScale)
|
|
readonly property real cornerRadiusS: Shape.radius("s", shapeScale)
|
|
readonly property real cornerRadiusM: Shape.radius("m", shapeScale)
|
|
readonly property real cornerRadiusL: Shape.radius("l", shapeScale)
|
|
readonly property real cornerRadiusLIncreased: Shape.radius("lIncreased", shapeScale)
|
|
readonly property real cornerRadiusXL: Shape.radius("xl", shapeScale)
|
|
readonly property real cornerRadiusXLIncreased: Shape.radius("xlIncreased", shapeScale)
|
|
readonly property real cornerRadiusXXL: Shape.radius("xxl", shapeScale)
|
|
readonly property real cornerRadiusFull: shapeScale > 0 ? 9999 : 0
|
|
readonly property real cornerRadiusSmall: cornerRadiusS
|
|
readonly property real cornerRadiusLarge: cornerRadiusL
|
|
readonly property int compositorRadiusOverride: {
|
|
if (typeof SettingsData === "undefined")
|
|
return -1;
|
|
if (!CompositorService.supportsLayoutConfig)
|
|
return -1;
|
|
const override = SettingsData[CompositorService.configKey + "LayoutRadiusOverride"];
|
|
return override === undefined ? -1 : override;
|
|
}
|
|
readonly property real windowRadius: compositorRadiusOverride >= 0 ? compositorRadiusOverride : cornerRadiusL
|
|
|
|
function scaledRadius(radius, limit) {
|
|
return Shape.scaledRadius(radius, limit, shapeScale);
|
|
}
|
|
|
|
function fullRadius(width, height) {
|
|
return Shape.fullRadius(width, height, shapeScale);
|
|
}
|
|
|
|
function buttonRadius(width, height, sizeHeight, pressed, round) {
|
|
return Shape.buttonRadius(width, height, sizeHeight, pressed, round, shapeScale);
|
|
}
|
|
|
|
readonly property real groupedListGap: spacingXXS
|
|
readonly property real groupedListInnerRadius: cornerRadiusXS
|
|
readonly property real groupedListOuterRadius: cornerRadiusL
|
|
|
|
property string fontFamily: {
|
|
if (typeof SettingsData === "undefined")
|
|
return DankCommon.Fonts.sans;
|
|
if (SettingsData.isGreeterMode && SettingsData.lockScreenFontFamily !== "")
|
|
return resolvedFontFamily(SettingsData.lockScreenFontFamily);
|
|
return resolvedFontFamily(SettingsData.fontFamily);
|
|
}
|
|
|
|
property string monoFontFamily: typeof SettingsData !== "undefined" ? resolvedMonoFontFamily(SettingsData.monoFontFamily) : DankCommon.Fonts.mono
|
|
property string displayFontFamily: typeof SettingsData !== "undefined" ? resolvedDisplayFontFamily(SettingsData.displayFontFamily) : DankCommon.Fonts.display
|
|
|
|
readonly property var fontChoices: [
|
|
{
|
|
"value": "ui",
|
|
"text": I18n.tr("Default")
|
|
},
|
|
{
|
|
"value": "display",
|
|
"text": I18n.tr("Display", "Display font role option")
|
|
}
|
|
].concat(DankCommon.Fonts.bundledFamilies.map(family => ({
|
|
"value": family,
|
|
"text": family
|
|
})))
|
|
|
|
function resolvedFontFamily(family) {
|
|
if (family === defaultFontFamily)
|
|
return DankCommon.Fonts.sans;
|
|
return family;
|
|
}
|
|
|
|
function resolvedMonoFontFamily(family) {
|
|
if (family === defaultMonoFontFamily)
|
|
return DankCommon.Fonts.mono;
|
|
return family;
|
|
}
|
|
|
|
function resolvedDisplayFontFamily(family) {
|
|
if (family === defaultDisplayFontFamily)
|
|
return DankCommon.Fonts.display;
|
|
return family;
|
|
}
|
|
|
|
property int fontWeight: typeof SettingsData !== "undefined" ? SettingsData.fontWeight : Font.Normal
|
|
readonly property int fontWeightMedium: shiftedFontWeight(Font.Medium)
|
|
readonly property int fontWeightBold: shiftedFontWeight(Font.Bold)
|
|
|
|
function shiftedFontWeight(weight) {
|
|
return Math.max(Font.Thin, Math.min(Font.Black, weight + fontWeight - Font.Normal));
|
|
}
|
|
|
|
property real fontScale: typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0
|
|
|
|
property real spacingXXS: 2
|
|
property real spacingXS: 4
|
|
property real spacingS: 8
|
|
property real spacingM: 12
|
|
property real spacingL: 16
|
|
property real spacingXL: 24
|
|
property real fontSizeSmall: Math.round(fontScale * 12)
|
|
property real fontSizeMedium: Math.round(fontScale * 14)
|
|
property real fontSizeLarge: Math.round(fontScale * 16)
|
|
property real fontSizeXLarge: Math.round(fontScale * 20)
|
|
property real fontSizeXXLarge: Math.round(fontScale * 28)
|
|
property real fontSizeDisplay: Math.round(fontScale * 36)
|
|
property real fontSizeDisplayLarge: Math.round(fontScale * 57)
|
|
property real barHeight: 48
|
|
property real iconSize: 24
|
|
property real iconSizeSmall: 16
|
|
property real iconSizeLarge: 32
|
|
readonly property real iconSizeMedium: 20
|
|
readonly property int smallBreakpoint: 480
|
|
readonly property int mediumBreakpoint: 768
|
|
readonly property real iconButtonSize: 40
|
|
readonly property real minimumTouchTargetSize: 48
|
|
readonly property real listItemHeight: 56
|
|
readonly property real listItemTwoLineHeight: 72
|
|
readonly property real avatarSize: 36
|
|
readonly property real sliderTrackHeight: 16
|
|
readonly property real sliderHandleWidth: 4
|
|
readonly property real sliderHandleWidthDesktop: 6
|
|
readonly property real sliderHandleWidthDesktopPressed: 4
|
|
readonly property real sliderHandleHeightDesktop: 32
|
|
readonly property real sliderHandleHeight: 44
|
|
readonly property real sliderHandleGap: 6
|
|
readonly property real sliderTrackHeightS: 24
|
|
readonly property real sliderHandleHeightS: 44
|
|
readonly property real sliderTrackHeightM: 40
|
|
readonly property real sliderHandleHeightM: 44
|
|
readonly property real sliderTrackHeightL: 56
|
|
readonly property real sliderHandleHeightL: 68
|
|
readonly property real sliderTrackHeightXL: 96
|
|
readonly property real sliderHandleHeightXL: 108
|
|
readonly property real switchTrackWidth: 52
|
|
readonly property real switchTrackHeight: 32
|
|
readonly property real switchOutlineWidth: 2
|
|
readonly property real switchThumbUnselected: 16
|
|
readonly property real switchThumbSelected: 24
|
|
readonly property real switchThumbPressed: 28
|
|
readonly property real sliderStopSize: 4
|
|
readonly property real sliderTickSize: 3
|
|
readonly property real menuItemHeight: 40
|
|
readonly property real outlineWidth: 1
|
|
readonly property real outlineWidthFocused: 2
|
|
readonly property real dividerWidth: 1
|
|
readonly property real focusRingWidth: SettingsData.focusRingEnabled ? SettingsData.focusRingWidth : 0
|
|
readonly property real focusRingOffset: 3
|
|
readonly property color focusRingColor: {
|
|
switch (SettingsData.focusRingColor) {
|
|
case "secondary":
|
|
return secondary;
|
|
case "outline":
|
|
return outline;
|
|
case "surfaceText":
|
|
return surfaceText;
|
|
default:
|
|
return primary;
|
|
}
|
|
}
|
|
readonly property color lockScreenContentColor: "#ffffff"
|
|
readonly property real lockScreenScrimAlpha: 0.4
|
|
readonly property real lockScreenBlur: 0.8
|
|
readonly property int lockScreenBlurMax: 32
|
|
readonly property color screenOffColor: "#000000"
|
|
readonly property real scrimAlpha: 0.55
|
|
readonly property color scrimColor: currentThemeData.scrim || "#000000"
|
|
readonly property real buttonHeightXXS: 28
|
|
readonly property real buttonHeightXS: 32
|
|
readonly property real buttonHeightS: 40
|
|
readonly property real buttonHeightM: 56
|
|
readonly property real buttonMinWidth: 58
|
|
readonly property real pressScale: 0.98
|
|
readonly property real iconEnterScale: 0.6
|
|
readonly property real osdHeight: sliderHandleHeight + spacingS * 2
|
|
readonly property real dialogMaxWidth: 560
|
|
readonly property real bottomSheetHandleWidth: 36
|
|
readonly property real bottomSheetHandleHeight: 4
|
|
readonly property real popupEnterScale: 0.92
|
|
readonly property real pendingOpacity: 0.6
|
|
readonly property real spinnerStrokeWidth: 2
|
|
readonly property real tabMinWidth: 64
|
|
readonly property real tabIndicatorHeight: 3
|
|
readonly property real tabIndicatorMinWidth: 24
|
|
readonly property real tabIndicatorInset: 2
|
|
readonly property real launcherTileSize: 120
|
|
readonly property real launcherImageRatio: 0.75
|
|
readonly property int launcherMaxVisibleRows: 8
|
|
readonly property real launcherWidthMicro: 500
|
|
readonly property real launcherWidthDefault: 620
|
|
readonly property real launcherWidthWide: 720
|
|
readonly property real launcherWidthLarge: 860
|
|
readonly property real launcherHeightDefault: 600
|
|
readonly property real launcherScreenMargin: 100
|
|
|
|
readonly property real fieldDefaultWidth: 200
|
|
readonly property real fieldHeight: Math.round(fontSizeMedium * 3)
|
|
readonly property real fieldHeightLarge: 48
|
|
readonly property real outlinedFieldLabelLineHeight: 16
|
|
readonly property real textFieldSpatialStiffness: 800
|
|
readonly property real textFieldSpatialDampingRatio: 1
|
|
readonly property real textFieldFastEffectsStiffness: 3800
|
|
readonly property real textFieldSlowEffectsStiffness: 800
|
|
readonly property real textEditHeight: Math.round(fontSizeMedium * 8)
|
|
readonly property real tooltipMaxWidth: 500
|
|
readonly property int tooltipDelay: 400
|
|
readonly property real menuMaxHeight: 400
|
|
readonly property real clockFaceSize: 250
|
|
readonly property real clockOuterRingRatio: 0.34
|
|
readonly property real clockInnerRingRatio: 0.2
|
|
readonly property real clockHandWidth: 2
|
|
readonly property real clockHandleSize: 40
|
|
readonly property real clockCenterSize: 8
|
|
readonly property int clockSwitchDelay: 100
|
|
readonly property real chipIconSize: 18
|
|
readonly property real buttonGroupExpandRatio: 0.15
|
|
readonly property color contrastDark: "#000000"
|
|
readonly property color contrastLight: "#ffffff"
|
|
|
|
property real panelTransparency: 0.85
|
|
property real popupTransparency: {
|
|
if (typeof SettingsData === "undefined")
|
|
return 1.0;
|
|
if (isConnectedEffect)
|
|
return SettingsData.frameOpacity !== undefined ? SettingsData.frameOpacity : 1.0;
|
|
return SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0;
|
|
}
|
|
|
|
function screenTransition() {
|
|
screenTransitionNeeded();
|
|
}
|
|
|
|
function switchTheme(themeName, savePrefs = true, enableTransition = true) {
|
|
if (enableTransition) {
|
|
screenTransition();
|
|
themeTransitionTimer.themeName = themeName;
|
|
themeTransitionTimer.savePrefs = savePrefs;
|
|
themeTransitionTimer.restart();
|
|
return;
|
|
}
|
|
|
|
if (themeName === dynamic) {
|
|
currentTheme = dynamic;
|
|
if (currentThemeCategory !== "registry")
|
|
currentThemeCategory = dynamic;
|
|
} else if (themeName === custom) {
|
|
currentTheme = custom;
|
|
if (currentThemeCategory !== "registry")
|
|
currentThemeCategory = custom;
|
|
if (typeof SettingsData !== "undefined" && SettingsData.customThemeFile) {
|
|
loadCustomThemeFromFile(SettingsData.customThemeFile);
|
|
}
|
|
} else if (themeName === "" && currentThemeCategory === "registry") {
|
|
// Registry category selected but no theme chosen yet
|
|
} else {
|
|
currentTheme = themeName;
|
|
if (currentThemeCategory !== "registry") {
|
|
currentThemeCategory = "generic";
|
|
}
|
|
}
|
|
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
|
|
if (savePrefs && typeof SettingsData !== "undefined" && !isGreeterMode) {
|
|
SettingsData.set("currentThemeCategory", currentThemeCategory);
|
|
SettingsData.set("currentThemeName", currentTheme);
|
|
}
|
|
|
|
if (!isGreeterMode) {
|
|
generateSystemThemesFromCurrentTheme();
|
|
}
|
|
}
|
|
|
|
function setLightMode(light, savePrefs = true, enableTransition = false) {
|
|
if (typeof SettingsData !== "undefined" && SettingsData.matugenSmartMode) {
|
|
SettingsData.matugenSmartMode = false;
|
|
SettingsData.saveSettings();
|
|
}
|
|
|
|
if (enableTransition) {
|
|
screenTransition();
|
|
lightModeTransitionTimer.lightMode = light;
|
|
lightModeTransitionTimer.savePrefs = savePrefs;
|
|
lightModeTransitionTimer.restart();
|
|
return;
|
|
}
|
|
|
|
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
|
|
if (savePrefs && typeof SessionData !== "undefined" && !isGreeterMode) {
|
|
SessionData.setLightMode(light);
|
|
}
|
|
|
|
if (!isGreeterMode) {
|
|
if (typeof SettingsData !== "undefined") {
|
|
SettingsData.updateCosmicThemeMode(light);
|
|
}
|
|
generateSystemThemesFromCurrentTheme();
|
|
}
|
|
}
|
|
|
|
function toggleLightMode(savePrefs = true) {
|
|
setLightMode(!isLightMode, savePrefs, true);
|
|
}
|
|
|
|
function getThemeColors(themeName) {
|
|
if (themeName === "custom" && customThemeData) {
|
|
return customThemeData;
|
|
}
|
|
return StockThemes.getThemeByName(themeName, isLightMode);
|
|
}
|
|
|
|
function switchThemeCategory(category, defaultTheme) {
|
|
screenTransition();
|
|
themeCategoryTransitionTimer.category = category;
|
|
themeCategoryTransitionTimer.defaultTheme = defaultTheme;
|
|
themeCategoryTransitionTimer.restart();
|
|
}
|
|
|
|
function loadCustomTheme(themeData) {
|
|
customThemeRawData = themeData;
|
|
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark";
|
|
|
|
var baseColors = {};
|
|
if (themeData.dark || themeData.light) {
|
|
baseColors = themeData[colorMode] || themeData.dark || themeData.light || {};
|
|
} else {
|
|
baseColors = themeData;
|
|
}
|
|
|
|
if (themeData.variants) {
|
|
const themeId = themeData.id || "";
|
|
|
|
if (themeData.variants.type === "multi" && themeData.variants.flavors && themeData.variants.accents) {
|
|
const defaults = themeData.variants.defaults || {};
|
|
const modeDefaults = defaults[colorMode] || defaults.dark || {};
|
|
const stored = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, modeDefaults, colorMode) : modeDefaults;
|
|
var flavorId = stored.flavor || modeDefaults.flavor || "";
|
|
const accentId = stored.accent || modeDefaults.accent || "";
|
|
var flavor = findVariant(themeData.variants.flavors, flavorId);
|
|
if (flavor) {
|
|
const hasCurrentModeColors = flavor[colorMode] && (flavor[colorMode].primary || flavor[colorMode].surface);
|
|
if (!hasCurrentModeColors) {
|
|
flavorId = modeDefaults.flavor || "";
|
|
flavor = findVariant(themeData.variants.flavors, flavorId);
|
|
}
|
|
}
|
|
const accent = findAccent(themeData.variants.accents, accentId);
|
|
if (flavor) {
|
|
const flavorColors = flavor[colorMode] || flavor.dark || flavor.light || {};
|
|
baseColors = mergeColors(baseColors, flavorColors);
|
|
}
|
|
if (accent && flavor) {
|
|
const accentColors = accent[flavor.id] || {};
|
|
baseColors = mergeColors(baseColors, accentColors);
|
|
}
|
|
customThemeData = baseColors;
|
|
generateSystemThemesFromCurrentTheme();
|
|
return;
|
|
}
|
|
|
|
if (themeData.variants.options && themeData.variants.options.length > 0) {
|
|
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, themeData.variants.default) : themeData.variants.default;
|
|
const variant = findVariant(themeData.variants.options, selectedVariantId);
|
|
if (variant) {
|
|
const variantColors = variant[colorMode] || variant.dark || variant.light || {};
|
|
customThemeData = mergeColors(baseColors, variantColors);
|
|
generateSystemThemesFromCurrentTheme();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
customThemeData = baseColors;
|
|
generateSystemThemesFromCurrentTheme();
|
|
}
|
|
|
|
function findVariant(options, variantId) {
|
|
if (!variantId || !options)
|
|
return null;
|
|
for (var i = 0; i < options.length; i++) {
|
|
if (options[i].id === variantId)
|
|
return options[i];
|
|
}
|
|
return options[0] || null;
|
|
}
|
|
|
|
function findAccent(accents, accentId) {
|
|
if (!accentId || !accents)
|
|
return null;
|
|
for (var i = 0; i < accents.length; i++) {
|
|
if (accents[i].id === accentId)
|
|
return accents[i];
|
|
}
|
|
return accents[0] || null;
|
|
}
|
|
|
|
function mergeColors(base, overlay) {
|
|
var result = JSON.parse(JSON.stringify(base));
|
|
for (var key in overlay) {
|
|
if (overlay[key])
|
|
result[key] = overlay[key];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function loadCustomThemeFromFile(filePath) {
|
|
customThemeFileView.path = Paths.expandTilde(filePath);
|
|
}
|
|
|
|
function reloadCustomThemeVariant() {
|
|
if (currentTheme !== "custom" || !customThemeRawData)
|
|
return;
|
|
loadCustomTheme(customThemeRawData);
|
|
}
|
|
|
|
property alias availableThemeNames: root._availableThemeNames
|
|
readonly property var _availableThemeNames: StockThemes.getAllThemeNames()
|
|
property string currentThemeName: currentTheme
|
|
|
|
property real notepadTransparency: SettingsData.notepadTransparencyOverride >= 0 ? SettingsData.notepadTransparencyOverride : floatingWindowTransparency
|
|
|
|
property bool widgetBackgroundHasAlpha: {
|
|
const colorMode = typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundColor : "sch";
|
|
return colorMode === "sth" || colorMode === "custom";
|
|
}
|
|
|
|
function safeColor(value, fallback) {
|
|
try {
|
|
if (value === undefined || value === null || value === "")
|
|
return fallback;
|
|
return Qt.color(value);
|
|
} catch (e) {
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
readonly property color widgetBackgroundCustomBaseColor: safeColor(typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundCustomColor : "#6750A4", primaryContainer)
|
|
readonly property real widgetBackgroundCustomStrength: Math.max(0, Math.min(1, typeof SettingsData !== "undefined" ? (SettingsData.widgetBackgroundCustomStrength ?? 0.4) : 0.4))
|
|
|
|
property var widgetBaseBackgroundColor: {
|
|
const colorMode = typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundColor : "sch";
|
|
switch (colorMode) {
|
|
case "s":
|
|
return surface;
|
|
case "sc":
|
|
return surfaceContainer;
|
|
case "sch":
|
|
return surfaceContainerHigh;
|
|
case "primaryContainer":
|
|
return primaryContainer;
|
|
case "secondaryContainer":
|
|
return secondaryContainer;
|
|
case "tertiaryContainer":
|
|
return tertiaryContainer;
|
|
case "custom":
|
|
return blend(surfaceContainerHigh, widgetBackgroundCustomBaseColor, widgetBackgroundCustomStrength);
|
|
case "sth":
|
|
default:
|
|
return surfaceTextHover;
|
|
}
|
|
}
|
|
|
|
property color widgetBaseHoverColor: {
|
|
const blended = blend(widgetBaseBackgroundColor, primary, 0.1);
|
|
return withAlpha(blended, Math.max(0.3, blended.a));
|
|
}
|
|
|
|
property color widgetIconColor: {
|
|
if (typeof SettingsData === "undefined") {
|
|
return surfaceText;
|
|
}
|
|
|
|
switch (SettingsData.widgetColorMode) {
|
|
case "colorful":
|
|
return surfaceText;
|
|
case "default":
|
|
default:
|
|
return surfaceText;
|
|
}
|
|
}
|
|
|
|
property color widgetInactiveIconColor: withAlpha(widgetIconColor, 0.6)
|
|
|
|
property color widgetTextColor: {
|
|
if (typeof SettingsData === "undefined") {
|
|
return surfaceText;
|
|
}
|
|
|
|
switch (SettingsData.widgetColorMode) {
|
|
case "colorful":
|
|
return primary;
|
|
case "default":
|
|
default:
|
|
return surfaceText;
|
|
}
|
|
}
|
|
|
|
function barIconSize(barThickness, offset, maximizeIcon, iconScale) {
|
|
const defaultOffset = offset !== undefined ? offset : -6;
|
|
const size = (maximizeIcon ?? false) ? iconSizeLarge : iconSize;
|
|
const s = iconScale !== undefined ? iconScale : 1.0;
|
|
|
|
return 2 * Math.round((barThickness / 48) * (size + defaultOffset) * s / 2);
|
|
}
|
|
|
|
function barTextSize(barThickness, fontScale, maximizeText) {
|
|
const scale = barThickness / 48;
|
|
const dankBarScale = fontScale !== undefined ? fontScale : 1.0;
|
|
const maxScale = (maximizeText ?? false) ? 1.5 : 1.0;
|
|
if (scale <= 0.75)
|
|
return Math.round(fontSizeSmall * 0.9 * dankBarScale * maxScale);
|
|
if (scale >= 1.25)
|
|
return Math.round(fontSizeMedium * dankBarScale * maxScale);
|
|
return Math.round(fontSizeSmall * dankBarScale * maxScale);
|
|
}
|
|
|
|
// !TODO: plugin API only (dms-plugins DankKDEConnect); fold into a parametrized BatteryService ladder and drop from Theme
|
|
function getBatteryIcon(level, isCharging, batteryAvailable) {
|
|
if (!batteryAvailable)
|
|
return "battery_std";
|
|
|
|
if (isCharging) {
|
|
if (level >= 90)
|
|
return "battery_charging_full";
|
|
if (level >= 80)
|
|
return "battery_charging_90";
|
|
if (level >= 60)
|
|
return "battery_charging_80";
|
|
if (level >= 50)
|
|
return "battery_charging_60";
|
|
if (level >= 30)
|
|
return "battery_charging_50";
|
|
if (level >= 20)
|
|
return "battery_charging_30";
|
|
return "battery_charging_20";
|
|
} else {
|
|
if (level >= 95)
|
|
return "battery_full";
|
|
if (level >= 85)
|
|
return "battery_6_bar";
|
|
if (level >= 70)
|
|
return "battery_5_bar";
|
|
if (level >= 55)
|
|
return "battery_4_bar";
|
|
if (level >= 40)
|
|
return "battery_3_bar";
|
|
if (level >= 25)
|
|
return "battery_2_bar";
|
|
if (level >= 10)
|
|
return "battery_1_bar";
|
|
return "battery_alert";
|
|
}
|
|
}
|
|
|
|
function getPowerProfileIcon(profile) {
|
|
switch (profile) {
|
|
case 0:
|
|
return "battery_saver";
|
|
case 1:
|
|
return "battery_std";
|
|
case 2:
|
|
return "flash_on";
|
|
default:
|
|
return "settings";
|
|
}
|
|
}
|
|
|
|
function getPowerProfileLabel(profile) {
|
|
switch (profile) {
|
|
case 0:
|
|
return I18n.tr("Power Saver", "power profile option");
|
|
case 1:
|
|
return I18n.tr("Balanced", "power profile option");
|
|
case 2:
|
|
return I18n.tr("Performance", "power profile option");
|
|
default:
|
|
return I18n.tr("Unknown", "power profile option");
|
|
}
|
|
}
|
|
|
|
function onLightModeChanged() {
|
|
if (currentTheme === "custom" && customThemeFileView.path) {
|
|
customThemeFileView.reload();
|
|
}
|
|
}
|
|
|
|
function setDesiredTheme(kind, value, isLight, iconTheme, matugenType, stockColors) {
|
|
if (!matugenAvailable) {
|
|
log.warn("matugen not available or disabled - cannot set system theme");
|
|
return;
|
|
}
|
|
|
|
if (workerRunning) {
|
|
log.info("Worker already running, queueing request");
|
|
pendingThemeRequest = {
|
|
kind,
|
|
value,
|
|
isLight,
|
|
iconTheme,
|
|
matugenType,
|
|
stockColors
|
|
};
|
|
return;
|
|
}
|
|
|
|
log.info("Setting desired theme -", kind, "mode:", isLight ? "light" : "dark", stockColors ? "(stock colors)" : "(dynamic)");
|
|
|
|
themeGenerationStarting();
|
|
|
|
const desired = {
|
|
"kind": kind,
|
|
"value": value,
|
|
"mode": (typeof SettingsData !== "undefined" && SettingsData.matugenSmartMode && kind === "image" && !stockColors) ? "smart" : (isLight ? "light" : "dark"),
|
|
"iconTheme": iconTheme || "System Default",
|
|
"matugenType": matugenType || "scheme-tonal-spot",
|
|
"runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true
|
|
};
|
|
|
|
log.debug("Starting matugen worker");
|
|
workerRunning = true;
|
|
|
|
const args = ["dms", "matugen", "queue", "--state-dir", stateDir, "--shell-dir", shellDir, "--config-dir", configDir, "--kind", desired.kind, "--value", desired.value, "--mode", desired.mode, "--icon-theme", desired.iconTheme, "--matugen-type", desired.matugenType,];
|
|
|
|
if (!desired.runUserTemplates) {
|
|
args.push("--run-user-templates=false");
|
|
}
|
|
if (stockColors) {
|
|
args.push("--stock-colors", JSON.stringify(stockColors));
|
|
}
|
|
if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal) {
|
|
args.push("--sync-mode-with-portal");
|
|
}
|
|
if (typeof SettingsData !== "undefined" && SettingsData.terminalsAlwaysDark) {
|
|
args.push("--terminals-always-dark");
|
|
}
|
|
if (typeof SettingsData !== "undefined" && SettingsData.matugenContrast !== 0) {
|
|
args.push("--contrast", SettingsData.matugenContrast.toString());
|
|
}
|
|
// Only sent when it would change something. A shell newer than the dms
|
|
// binary is a supported setup (DMS_SHELL_DIR / -c), and an older binary
|
|
// exits with "unknown flag: --source-mode" rather than ignoring it, so
|
|
// the default must not put the flag on the command line at all.
|
|
if (typeof SettingsData !== "undefined" && SettingsData.matugenSourceMode && SettingsData.matugenSourceMode !== "dominant") {
|
|
args.push("--source-mode", SettingsData.matugenSourceMode);
|
|
}
|
|
|
|
if (typeof SettingsData !== "undefined") {
|
|
const skipTemplates = [];
|
|
if (!SettingsData.runDmsMatugenTemplates) {
|
|
skipTemplates.push("gtk", "nvim", "niri", "qt5ct", "qt6ct", "qtengine", "fcitx5", "firefox", "pywalfox", "zenbrowser", "vesktop", "vencord", "equibop", "ghostty", "kitty", "foot", "alacritty", "wezterm", "dgop", "kcolorscheme", "vscode", "emacs", "zed");
|
|
} else {
|
|
if (!SettingsData.matugenTemplateGtk)
|
|
skipTemplates.push("gtk");
|
|
if (!SettingsData.matugenTemplateNiri)
|
|
skipTemplates.push("niri");
|
|
if (!SettingsData.matugenTemplateHyprland)
|
|
skipTemplates.push("hyprland");
|
|
if (!SettingsData.matugenTemplateMangowc)
|
|
skipTemplates.push("mangowc");
|
|
if (!SettingsData.matugenTemplateQt5ct)
|
|
skipTemplates.push("qt5ct");
|
|
if (!SettingsData.matugenTemplateQt6ct)
|
|
skipTemplates.push("qt6ct");
|
|
if (!SettingsData.matugenTemplateQtengine)
|
|
skipTemplates.push("qtengine");
|
|
if (!SettingsData.matugenTemplateFcitx5)
|
|
skipTemplates.push("fcitx5");
|
|
if (!SettingsData.matugenTemplateFirefox)
|
|
skipTemplates.push("firefox");
|
|
if (!SettingsData.matugenTemplatePywalfox)
|
|
skipTemplates.push("pywalfox");
|
|
if (!SettingsData.matugenTemplateZenBrowser)
|
|
skipTemplates.push("zenbrowser");
|
|
if (!SettingsData.matugenTemplateVesktop)
|
|
skipTemplates.push("vesktop");
|
|
if (!SettingsData.matugenTemplateVencord)
|
|
skipTemplates.push("vencord");
|
|
if (!SettingsData.matugenTemplateEquibop)
|
|
skipTemplates.push("equibop");
|
|
if (!SettingsData.matugenTemplateGhostty)
|
|
skipTemplates.push("ghostty");
|
|
if (!SettingsData.matugenTemplateKitty)
|
|
skipTemplates.push("kitty");
|
|
if (!SettingsData.matugenTemplateFoot)
|
|
skipTemplates.push("foot");
|
|
if (!SettingsData.matugenTemplateNeovim)
|
|
skipTemplates.push("nvim");
|
|
if (!SettingsData.matugenTemplateAlacritty)
|
|
skipTemplates.push("alacritty");
|
|
if (!SettingsData.matugenTemplateWezterm)
|
|
skipTemplates.push("wezterm");
|
|
if (!SettingsData.matugenTemplateDgop)
|
|
skipTemplates.push("dgop");
|
|
if (!SettingsData.matugenTemplateKcolorscheme)
|
|
skipTemplates.push("kcolorscheme");
|
|
if (!SettingsData.matugenTemplateVscode)
|
|
skipTemplates.push("vscode");
|
|
if (!SettingsData.matugenTemplateEmacs)
|
|
skipTemplates.push("emacs");
|
|
if (!SettingsData.matugenTemplateZed)
|
|
skipTemplates.push("zed");
|
|
}
|
|
if (skipTemplates.length > 0) {
|
|
args.push("--skip-templates", skipTemplates.join(","));
|
|
}
|
|
}
|
|
|
|
systemThemeGenerator.command = args;
|
|
systemThemeGenerator.running = true;
|
|
}
|
|
|
|
function generateSystemThemesFromCurrentTheme() {
|
|
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
|
|
if (!matugenAvailable || isGreeterMode)
|
|
return;
|
|
|
|
_lastGenerateMs = Date.now();
|
|
_pendingGenerateParams = true;
|
|
_themeGenerateDebounce.restart();
|
|
}
|
|
|
|
function _executeThemeGeneration() {
|
|
if (!_pendingGenerateParams)
|
|
return;
|
|
_pendingGenerateParams = null;
|
|
|
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode);
|
|
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default";
|
|
|
|
if (currentTheme === dynamic) {
|
|
if (!rawWallpaperPath) {
|
|
log.warn("Auto theme has no wallpaper - skipping matugen");
|
|
return;
|
|
}
|
|
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot";
|
|
const kind = rawWallpaperPath.startsWith("#") ? "hex" : "image";
|
|
setDesiredTheme(kind, rawWallpaperPath, isLight, iconTheme, selectedMatugenType, null);
|
|
return;
|
|
}
|
|
|
|
let darkTheme, lightTheme;
|
|
if (currentTheme === "custom") {
|
|
if (customThemeRawData && (customThemeRawData.dark || customThemeRawData.light)) {
|
|
darkTheme = customThemeRawData.dark || customThemeRawData.light;
|
|
lightTheme = customThemeRawData.light || customThemeRawData.dark;
|
|
|
|
if (customThemeRawData.variants) {
|
|
const themeId = customThemeRawData.id || "";
|
|
|
|
if (customThemeRawData.variants.type === "multi" && customThemeRawData.variants.flavors && customThemeRawData.variants.accents) {
|
|
const defaults = customThemeRawData.variants.defaults || {};
|
|
const darkDefaults = defaults.dark || {};
|
|
const lightDefaults = defaults.light || defaults.dark || {};
|
|
const storedDark = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults, "dark") : darkDefaults;
|
|
const storedLight = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults, "light") : lightDefaults;
|
|
const darkFlavorId = storedDark.flavor || darkDefaults.flavor || "";
|
|
const lightFlavorId = storedLight.flavor || lightDefaults.flavor || "";
|
|
const darkAccentId = storedDark.accent || darkDefaults.accent || "";
|
|
const lightAccentId = storedLight.accent || lightDefaults.accent || "";
|
|
const darkFlavor = findVariant(customThemeRawData.variants.flavors, darkFlavorId);
|
|
const lightFlavor = findVariant(customThemeRawData.variants.flavors, lightFlavorId);
|
|
const darkAccent = findAccent(customThemeRawData.variants.accents, darkAccentId);
|
|
const lightAccent = findAccent(customThemeRawData.variants.accents, lightAccentId);
|
|
if (darkFlavor) {
|
|
darkTheme = mergeColors(darkTheme, darkFlavor.dark || {});
|
|
if (darkAccent)
|
|
darkTheme = mergeColors(darkTheme, darkAccent[darkFlavor.id] || {});
|
|
}
|
|
if (lightFlavor) {
|
|
lightTheme = mergeColors(lightTheme, lightFlavor.light || {});
|
|
if (lightAccent)
|
|
lightTheme = mergeColors(lightTheme, lightAccent[lightFlavor.id] || {});
|
|
}
|
|
} else if (customThemeRawData.variants.options) {
|
|
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, customThemeRawData.variants.default) : customThemeRawData.variants.default;
|
|
const variant = findVariant(customThemeRawData.variants.options, selectedVariantId);
|
|
if (variant) {
|
|
darkTheme = mergeColors(darkTheme, variant.dark || {});
|
|
lightTheme = mergeColors(lightTheme, variant.light || {});
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
darkTheme = customThemeData;
|
|
lightTheme = customThemeData;
|
|
}
|
|
} else {
|
|
darkTheme = StockThemes.getThemeByName(currentTheme, false);
|
|
lightTheme = StockThemes.getThemeByName(currentTheme, true);
|
|
}
|
|
|
|
if (!darkTheme || !darkTheme.primary) {
|
|
log.warn("Theme data not available for:", currentTheme);
|
|
return;
|
|
}
|
|
|
|
const stockColors = buildMatugenColorsFromTheme(darkTheme, lightTheme);
|
|
const themeData = isLight ? lightTheme : darkTheme;
|
|
setDesiredTheme("hex", themeData.primary, isLight, iconTheme, themeData.matugen_type, stockColors);
|
|
}
|
|
|
|
function buildMatugenColorsFromTheme(darkTheme, lightTheme) {
|
|
const colors = {};
|
|
const isLight = SessionData !== "undefined" && SessionData.isLightMode;
|
|
|
|
function addColor(matugenKey, darkVal, lightVal) {
|
|
if (!darkVal && !lightVal)
|
|
return;
|
|
colors[matugenKey] = {
|
|
"dark": {
|
|
"color": String(darkVal || lightVal)
|
|
},
|
|
"light": {
|
|
"color": String(lightVal || darkVal)
|
|
},
|
|
"default": {
|
|
"color": String((isLight && lightVal) ? lightVal : darkVal)
|
|
}
|
|
};
|
|
}
|
|
|
|
function get(theme, key, fallback) {
|
|
return theme[key] || fallback;
|
|
}
|
|
|
|
addColor("primary", darkTheme.primary, lightTheme.primary);
|
|
addColor("on_primary", darkTheme.primaryText, lightTheme.primaryText);
|
|
addColor("primary_container", darkTheme.primaryContainer, lightTheme.primaryContainer);
|
|
addColor("on_primary_container", darkTheme.primaryContainerText || darkTheme.surfaceText, lightTheme.primaryContainerText || lightTheme.surfaceText);
|
|
addColor("secondary", darkTheme.secondary, lightTheme.secondary);
|
|
addColor("on_secondary", darkTheme.secondaryText || darkTheme.primaryText, lightTheme.secondaryText || lightTheme.primaryText);
|
|
addColor("secondary_container", darkTheme.secondaryContainer || darkTheme.surfaceContainerHigh, lightTheme.secondaryContainer || lightTheme.surfaceContainerHigh);
|
|
addColor("on_secondary_container", darkTheme.secondaryContainerText || darkTheme.surfaceText, lightTheme.secondaryContainerText || lightTheme.surfaceText);
|
|
addColor("tertiary", darkTheme.tertiary || darkTheme.secondary, lightTheme.tertiary || lightTheme.secondary);
|
|
addColor("on_tertiary", darkTheme.tertiaryText || darkTheme.secondaryText || darkTheme.primaryText, lightTheme.tertiaryText || lightTheme.secondaryText || lightTheme.primaryText);
|
|
addColor("tertiary_container", darkTheme.tertiaryContainer || darkTheme.secondaryContainer || darkTheme.surfaceContainerHigh, lightTheme.tertiaryContainer || lightTheme.secondaryContainer || lightTheme.surfaceContainerHigh);
|
|
addColor("on_tertiary_container", darkTheme.tertiaryContainerText || darkTheme.surfaceText, lightTheme.tertiaryContainerText || lightTheme.surfaceText);
|
|
addColor("error", darkTheme.error || "#F2B8B5", lightTheme.error || "#B3261E");
|
|
addColor("on_error", darkTheme.errorText || "#601410", lightTheme.errorText || "#FFFFFF");
|
|
addColor("error_container", darkTheme.errorContainer || "#8C1D18", lightTheme.errorContainer || "#F9DEDC");
|
|
addColor("on_error_container", darkTheme.errorContainerText || "#F9DEDC", lightTheme.errorContainerText || "#410E0B");
|
|
addColor("surface", darkTheme.surface, lightTheme.surface);
|
|
addColor("on_surface", darkTheme.surfaceText, lightTheme.surfaceText);
|
|
addColor("surface_variant", darkTheme.surfaceVariant, lightTheme.surfaceVariant);
|
|
addColor("on_surface_variant", darkTheme.surfaceVariantText, lightTheme.surfaceVariantText);
|
|
addColor("surface_tint", darkTheme.surfaceTint, lightTheme.surfaceTint);
|
|
addColor("background", darkTheme.background, lightTheme.background);
|
|
addColor("on_background", darkTheme.backgroundText, lightTheme.backgroundText);
|
|
addColor("outline", darkTheme.outline, lightTheme.outline);
|
|
addColor("outline_variant", darkTheme.outlineVariant || darkTheme.surfaceVariant, lightTheme.outlineVariant || lightTheme.surfaceVariant);
|
|
addColor("surface_container", darkTheme.surfaceContainer, lightTheme.surfaceContainer);
|
|
addColor("surface_container_high", darkTheme.surfaceContainerHigh, lightTheme.surfaceContainerHigh);
|
|
addColor("surface_container_highest", darkTheme.surfaceContainerHighest || darkTheme.surfaceContainerHigh, lightTheme.surfaceContainerHighest || lightTheme.surfaceContainerHigh);
|
|
addColor("surface_container_low", darkTheme.surfaceContainerLow || darkTheme.surface, lightTheme.surfaceContainerLow || lightTheme.surface);
|
|
addColor("surface_container_lowest", darkTheme.surfaceContainerLowest || darkTheme.background, lightTheme.surfaceContainerLowest || lightTheme.background);
|
|
addColor("surface_bright", darkTheme.surfaceBright || darkTheme.surfaceContainerHighest || darkTheme.surfaceContainerHigh, lightTheme.surfaceBright || lightTheme.surface);
|
|
addColor("surface_dim", darkTheme.surfaceDim || darkTheme.background, lightTheme.surfaceDim || lightTheme.surfaceContainer);
|
|
addColor("inverse_surface", darkTheme.inverseSurface || lightTheme.surface, lightTheme.inverseSurface || darkTheme.surface);
|
|
addColor("inverse_on_surface", darkTheme.inverseOnSurface || lightTheme.surfaceText, lightTheme.inverseOnSurface || darkTheme.surfaceText);
|
|
addColor("inverse_primary", darkTheme.inversePrimary || lightTheme.primary, lightTheme.inversePrimary || darkTheme.primary);
|
|
addColor("scrim", darkTheme.scrim || "#000000", lightTheme.scrim || "#000000");
|
|
addColor("shadow", darkTheme.shadow || "#000000", lightTheme.shadow || "#000000");
|
|
addColor("source_color", darkTheme.primary, lightTheme.primary);
|
|
addColor("primary_fixed", darkTheme.primaryFixed || darkTheme.primaryContainer, lightTheme.primaryFixed || lightTheme.primaryContainer);
|
|
addColor("primary_fixed_dim", darkTheme.primaryFixedDim || darkTheme.primary, lightTheme.primaryFixedDim || lightTheme.primary);
|
|
addColor("on_primary_fixed", darkTheme.onPrimaryFixed || darkTheme.primaryText, lightTheme.onPrimaryFixed || lightTheme.primaryText);
|
|
addColor("on_primary_fixed_variant", darkTheme.onPrimaryFixedVariant || darkTheme.primaryText, lightTheme.onPrimaryFixedVariant || lightTheme.primaryText);
|
|
addColor("secondary_fixed", darkTheme.secondaryFixed || darkTheme.secondary, lightTheme.secondaryFixed || lightTheme.secondary);
|
|
addColor("secondary_fixed_dim", darkTheme.secondaryFixedDim || darkTheme.secondary, lightTheme.secondaryFixedDim || lightTheme.secondary);
|
|
addColor("on_secondary_fixed", darkTheme.onSecondaryFixed || darkTheme.primaryText, lightTheme.onSecondaryFixed || lightTheme.primaryText);
|
|
addColor("on_secondary_fixed_variant", darkTheme.onSecondaryFixedVariant || darkTheme.primaryText, lightTheme.onSecondaryFixedVariant || lightTheme.primaryText);
|
|
addColor("tertiary_fixed", darkTheme.tertiaryFixed || darkTheme.tertiary || darkTheme.secondary, lightTheme.tertiaryFixed || lightTheme.tertiary || lightTheme.secondary);
|
|
addColor("tertiary_fixed_dim", darkTheme.tertiaryFixedDim || darkTheme.tertiary || darkTheme.secondary, lightTheme.tertiaryFixedDim || lightTheme.tertiary || lightTheme.secondary);
|
|
addColor("on_tertiary_fixed", darkTheme.onTertiaryFixed || darkTheme.primaryText, lightTheme.onTertiaryFixed || lightTheme.primaryText);
|
|
addColor("on_tertiary_fixed_variant", darkTheme.onTertiaryFixedVariant || darkTheme.primaryText, lightTheme.onTertiaryFixedVariant || lightTheme.primaryText);
|
|
|
|
return colors;
|
|
}
|
|
|
|
function refreshGtkTheme() {
|
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode);
|
|
const theme = isLight ? "adw-gtk3" : "adw-gtk3-dark";
|
|
const schema = "org.gnome.desktop.interface";
|
|
const key = "gtk-theme";
|
|
const reset = GSettings.setCmd(schema, key, "");
|
|
const apply = GSettings.setCmd(schema, key, theme);
|
|
|
|
Proc.runCommand("gtkRefresher", ["sh", "-c", `${reset}; ${apply}`], (output, exitCode) => {
|
|
if (exitCode !== 0) {
|
|
log.warn("Failed to refresh gtk-theme");
|
|
}
|
|
});
|
|
}
|
|
|
|
function patchGtk3colors() {
|
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode);
|
|
Proc.runCommand("gtk3Patcher", ["bash", shellDir + "/scripts/gtk.sh", configDir, "patch", isLight], (output, exitCode) => {
|
|
switch (exitCode) {
|
|
case 0:
|
|
refreshGtkTheme();
|
|
break;
|
|
case 2:
|
|
break;
|
|
default:
|
|
log.warn(`Failed to patch GTK3 colors: ${output}`);
|
|
}
|
|
});
|
|
}
|
|
|
|
function applyGtkColors() {
|
|
if (!matugenAvailable) {
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.showError(I18n.tr("matugen not available or disabled - cannot apply %1 colors", "error toast, %1 is GTK or Qt").arg("GTK"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "true" : "false";
|
|
Proc.runCommand("gtkApplier", ["bash", shellDir + "/scripts/gtk.sh", configDir, "apply", isLight], (output, exitCode) => {
|
|
if (exitCode === 0) {
|
|
if (typeof ToastService !== "undefined" && !root.matugenToastSuppressed) {
|
|
ToastService.showInfo(I18n.tr("GTK colors applied successfully"));
|
|
}
|
|
} else {
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.showError(I18n.tr("Failed to apply %1 colors", "error toast, %1 is GTK or Qt").arg("GTK"));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function applyQtColors() {
|
|
if (!matugenAvailable) {
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.showError(I18n.tr("matugen not available or disabled - cannot apply %1 colors").arg("Qt"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
const isQtengineActive = SettingsData.qtengineActive;
|
|
let pendingAppliers = isQtengineActive ? 2 : 1;
|
|
let anyApplierSucceeded = false;
|
|
let qtengineFailed = false;
|
|
|
|
const finishApplyQtColors = succeeded => {
|
|
anyApplierSucceeded = anyApplierSucceeded || succeeded;
|
|
pendingAppliers -= 1;
|
|
if (pendingAppliers !== 0)
|
|
return;
|
|
if (typeof ToastService === "undefined")
|
|
return;
|
|
if (anyApplierSucceeded && !qtengineFailed) {
|
|
ToastService.showInfo(I18n.tr("Qt colors applied successfully"));
|
|
} else {
|
|
ToastService.showError(I18n.tr("Failed to apply %1 colors").arg("Qt"));
|
|
}
|
|
};
|
|
|
|
Proc.runCommand("qtApplier", ["bash", shellDir + "/scripts/qt.sh", configDir], (output, exitCode) => {
|
|
finishApplyQtColors(exitCode === 0);
|
|
});
|
|
|
|
if (isQtengineActive) {
|
|
Proc.runCommand("qtengineApplier", [Proc.dmsBin, "matugen", "qtengine", "--config-dir", configDir], (output, exitCode) => {
|
|
qtengineFailed = exitCode !== 0;
|
|
finishApplyQtColors(exitCode === 0);
|
|
});
|
|
}
|
|
}
|
|
|
|
function withAlpha(c, a) {
|
|
if (!c || c.r === undefined)
|
|
return Qt.rgba(0, 0, 0, 0);
|
|
return Qt.rgba(c.r, c.g, c.b, a);
|
|
}
|
|
|
|
function blendAlpha(c, a) {
|
|
if (!c || c.r === undefined)
|
|
return Qt.rgba(0, 0, 0, 0);
|
|
return Qt.rgba(c.r, c.g, c.b, c.a * a);
|
|
}
|
|
|
|
function hoverTint(base) {
|
|
const factor = 1.2;
|
|
return isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
|
|
}
|
|
|
|
function blend(c1, c2, r) {
|
|
return Qt.rgba(c1.r * (1 - r) + c2.r * r, c1.g * (1 - r) + c2.g * r, c1.b * (1 - r) + c2.b * r, c1.a * (1 - r) + c2.a * r);
|
|
}
|
|
|
|
function luminance(c) {
|
|
if (!c || c.r === undefined)
|
|
return 0;
|
|
return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
|
|
}
|
|
|
|
function isLightColor(c, threshold = 0.5) {
|
|
return luminance(c) > threshold;
|
|
}
|
|
|
|
function getFillMode(modeName) {
|
|
switch (modeName) {
|
|
case "Stretch":
|
|
return Image.Stretch;
|
|
case "Fit":
|
|
case "PreserveAspectFit":
|
|
return Image.PreserveAspectFit;
|
|
case "Fill":
|
|
case "PreserveAspectCrop":
|
|
return Image.PreserveAspectCrop;
|
|
case "Tile":
|
|
return Image.Tile;
|
|
case "TileVertically":
|
|
return Image.TileVertically;
|
|
case "TileHorizontally":
|
|
return Image.TileHorizontally;
|
|
case "Pad":
|
|
return Image.Pad;
|
|
default:
|
|
return Image.PreserveAspectCrop;
|
|
}
|
|
}
|
|
|
|
// Returns numeric fillMode value for shader use (matches shader calculateUV logic)
|
|
function getShaderFillMode(modeName) {
|
|
switch (modeName) {
|
|
case "Stretch":
|
|
return 0;
|
|
case "Fit":
|
|
case "PreserveAspectFit":
|
|
return 1;
|
|
case "Fill":
|
|
case "PreserveAspectCrop":
|
|
return 2;
|
|
case "Tile":
|
|
return 3;
|
|
case "TileVertically":
|
|
return 4;
|
|
case "TileHorizontally":
|
|
return 5;
|
|
case "Pad":
|
|
return 6;
|
|
case "Scrolling":
|
|
return 7;
|
|
default:
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
function snap(value, dpr) {
|
|
const s = dpr || 1;
|
|
return Math.round(value * s) / s;
|
|
}
|
|
|
|
// Qt rounds a centred anchor offset to whole pixels, so a box must share its content's parity
|
|
function snapEven(value, dpr) {
|
|
const s = dpr || 1;
|
|
return 2 * Math.round(value * s / 2) / s;
|
|
}
|
|
|
|
function px(value, dpr) {
|
|
const s = dpr || 1;
|
|
return Math.round(value * s) / s;
|
|
}
|
|
|
|
function barWidgetThickness(innerPadding, dpr) {
|
|
return snapEven(Math.max(20, 26 + innerPadding * 0.6), dpr);
|
|
}
|
|
|
|
function barThickness(innerPadding, dpr) {
|
|
return snapEven(Math.max(barWidgetThickness(innerPadding, dpr) + innerPadding + 4, barHeight - 4 - (8 - innerPadding)), dpr);
|
|
}
|
|
|
|
function hairline(dpr) {
|
|
return 1 / (dpr || 1);
|
|
}
|
|
|
|
function invertHex(hex) {
|
|
hex = hex.replace('#', '');
|
|
|
|
if (!/^[0-9A-Fa-f]{6}$/.test(hex)) {
|
|
return hex;
|
|
}
|
|
|
|
const r = parseInt(hex.substr(0, 2), 16);
|
|
const g = parseInt(hex.substr(2, 2), 16);
|
|
const b = parseInt(hex.substr(4, 2), 16);
|
|
|
|
const invR = (255 - r).toString(16).padStart(2, '0');
|
|
const invG = (255 - g).toString(16).padStart(2, '0');
|
|
const invB = (255 - b).toString(16).padStart(2, '0');
|
|
|
|
return `#${invR}${invG}${invB}`;
|
|
}
|
|
|
|
property var baseLogoColor: {
|
|
if (typeof SettingsData === "undefined")
|
|
return "";
|
|
const colorOverride = SettingsData.launcherLogoColorOverride;
|
|
if (!colorOverride || colorOverride === "")
|
|
return "";
|
|
if (colorOverride === "primary")
|
|
return primary;
|
|
if (colorOverride === "surface")
|
|
return surfaceText;
|
|
return colorOverride;
|
|
}
|
|
|
|
property var effectiveLogoColor: {
|
|
if (typeof SettingsData === "undefined")
|
|
return "";
|
|
|
|
const colorOverride = SettingsData.launcherLogoColorOverride;
|
|
if (!colorOverride || colorOverride === "")
|
|
return "";
|
|
|
|
if (colorOverride === "primary")
|
|
return primary;
|
|
if (colorOverride === "surface")
|
|
return surfaceText;
|
|
|
|
if (!SettingsData.launcherLogoColorInvertOnMode) {
|
|
return colorOverride;
|
|
}
|
|
|
|
if (isLightMode) {
|
|
return invertHex(colorOverride);
|
|
}
|
|
|
|
return colorOverride;
|
|
}
|
|
|
|
Process {
|
|
id: systemThemeGenerator
|
|
running: false
|
|
stdout: SplitParser {
|
|
onRead: data => log.info("Theme worker:", data)
|
|
}
|
|
stderr: SplitParser {
|
|
onRead: data => log.warn("Theme worker:", data)
|
|
}
|
|
|
|
onExited: exitCode => {
|
|
workerRunning = false;
|
|
const currentMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark";
|
|
|
|
switch (exitCode) {
|
|
case 0:
|
|
log.info("Matugen worker completed successfully");
|
|
root.matugenCompleted(currentMode, "success");
|
|
break;
|
|
case 2:
|
|
log.debug("Matugen worker completed with code 2 (no changes needed)");
|
|
root.matugenCompleted(currentMode, "no-changes");
|
|
break;
|
|
default:
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.showError(I18n.tr("Theme worker failed (%1)", "error toast, %1 is a process exit code").arg(exitCode));
|
|
}
|
|
log.warn("Matugen worker failed with exit code:", exitCode);
|
|
root.matugenCompleted(currentMode, "error");
|
|
}
|
|
|
|
if (!pendingThemeRequest) {
|
|
if (SettingsData.matugenTemplateGtk)
|
|
patchGtk3colors();
|
|
return;
|
|
}
|
|
|
|
const req = pendingThemeRequest;
|
|
pendingThemeRequest = null;
|
|
log.info("Processing queued theme request");
|
|
setDesiredTheme(req.kind, req.value, req.isLight, req.iconTheme, req.matugenType, req.stockColors);
|
|
}
|
|
}
|
|
|
|
FileView {
|
|
id: customThemeFileView
|
|
blockLoading: false
|
|
watchChanges: currentTheme === "custom"
|
|
|
|
function parseAndLoadTheme() {
|
|
try {
|
|
var themeData = JSON.parse(customThemeFileView.text());
|
|
loadCustomTheme(themeData);
|
|
} catch (e) {
|
|
ToastService.showError(I18n.tr("Invalid JSON format: %1", "custom theme file error toast, %1 is the error message").arg(e.message));
|
|
}
|
|
}
|
|
|
|
onLoaded: {
|
|
parseAndLoadTheme();
|
|
}
|
|
|
|
onFileChanged: {
|
|
customThemeFileView.reload();
|
|
}
|
|
|
|
onLoadFailed: function (error) {
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.showError(I18n.tr("Failed to read theme file: %1", "error toast, %1 is the error message").arg(error));
|
|
}
|
|
}
|
|
}
|
|
|
|
readonly property string _greeterCacheDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"
|
|
|
|
property string greeterColorsBaseDir: root._greeterCacheDir
|
|
|
|
function setGreeterColorsBaseDir(dir) {
|
|
const next = dir || root._greeterCacheDir;
|
|
if (greeterColorsBaseDir === next)
|
|
return;
|
|
greeterColorsBaseDir = next;
|
|
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
|
dynamicColorsFileView.reload();
|
|
}
|
|
|
|
function resetGreeterColorsBaseDir() {
|
|
setGreeterColorsBaseDir(root._greeterCacheDir);
|
|
}
|
|
|
|
FileView {
|
|
id: dynamicColorsFileView
|
|
path: {
|
|
if (SessionData.isGreeterMode)
|
|
return root.greeterColorsBaseDir ? (root.greeterColorsBaseDir + "/colors.json") : "";
|
|
return stateDir + "/dms-colors.json";
|
|
}
|
|
blockLoading: false
|
|
watchChanges: !SessionData.isGreeterMode
|
|
|
|
function parseAndLoadColors() {
|
|
try {
|
|
const colorsText = dynamicColorsFileView.text();
|
|
if (colorsText) {
|
|
root.matugenColors = JSON.parse(colorsText);
|
|
if (typeof SettingsData !== "undefined" && SettingsData.matugenSmartMode && currentTheme === dynamic && root.matugenColors && root.matugenColors.mode && typeof SessionData !== "undefined" && !SessionData.isSwitchingMode) {
|
|
const resolvedLight = root.matugenColors.mode === "light";
|
|
if (SessionData.isLightMode !== resolvedLight) {
|
|
SessionData.setLightMode(resolvedLight, true);
|
|
SettingsData.updateCosmicThemeMode(resolvedLight);
|
|
}
|
|
}
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.clearWallpaperError();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log.error("Failed to parse dynamic colors:", e);
|
|
if (typeof ToastService !== "undefined") {
|
|
ToastService.wallpaperErrorStatus = "error";
|
|
ToastService.showError(I18n.tr("Dynamic colors parse error: %1", "error toast, %1 is the error message").arg(e.message));
|
|
}
|
|
}
|
|
}
|
|
|
|
onLoaded: {
|
|
_colorsRetryCount = 0;
|
|
if (currentTheme === dynamic)
|
|
colorsFileLoadFailed = false;
|
|
parseAndLoadColors();
|
|
}
|
|
|
|
onFileChanged: {
|
|
dynamicColorsFileView.reload();
|
|
}
|
|
|
|
onLoadFailed: function (error) {
|
|
if (currentTheme !== dynamic)
|
|
return;
|
|
|
|
if (SessionData.isGreeterMode)
|
|
return;
|
|
|
|
if (workerRunning) {
|
|
colorsReloadRetry.restart();
|
|
return;
|
|
}
|
|
|
|
if (_colorsRetryCount < 3) {
|
|
_colorsRetryCount++;
|
|
colorsReloadRetry.restart();
|
|
return;
|
|
}
|
|
|
|
colorsFileLoadFailed = true;
|
|
const stale = Date.now() - _lastGenerateMs > 5000;
|
|
if (matugenAvailable && rawWallpaperPath && stale) {
|
|
log.debug("Dynamic colors unrecoverable, regenerating");
|
|
generateSystemThemesFromCurrentTheme();
|
|
}
|
|
}
|
|
|
|
onPathChanged: {
|
|
colorsFileLoadFailed = false;
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: colorsReloadRetry
|
|
interval: 150
|
|
repeat: false
|
|
onTriggered: dynamicColorsFileView.reload()
|
|
}
|
|
|
|
IpcHandler {
|
|
target: "theme"
|
|
|
|
function toggle(): string {
|
|
root.toggleLightMode();
|
|
return root.isLightMode ? "dark" : "light";
|
|
}
|
|
|
|
function light(): string {
|
|
root.setLightMode(true, true, true);
|
|
return "light";
|
|
}
|
|
|
|
function dark(): string {
|
|
root.setLightMode(false, true, true);
|
|
return "dark";
|
|
}
|
|
|
|
function getMode(): string {
|
|
return root.isLightMode ? "light" : "dark";
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: _themeGenerateDebounce
|
|
interval: 100
|
|
repeat: false
|
|
onTriggered: root._executeThemeGeneration()
|
|
}
|
|
|
|
// These timers are for screen transitions, since sometimes QML still beats the niri call
|
|
Timer {
|
|
id: themeTransitionTimer
|
|
interval: 50
|
|
repeat: false
|
|
property string themeName: ""
|
|
property bool savePrefs: true
|
|
onTriggered: root.switchTheme(themeName, savePrefs, false)
|
|
}
|
|
|
|
Timer {
|
|
id: lightModeTransitionTimer
|
|
interval: 100
|
|
repeat: false
|
|
property bool lightMode: false
|
|
property bool savePrefs: true
|
|
onTriggered: root.setLightMode(lightMode, savePrefs, false)
|
|
}
|
|
|
|
Timer {
|
|
id: themeCategoryTransitionTimer
|
|
interval: 50
|
|
repeat: false
|
|
property string category: ""
|
|
property string defaultTheme: ""
|
|
onTriggered: {
|
|
root.currentThemeCategory = category;
|
|
root.switchTheme(defaultTheme, true, false);
|
|
}
|
|
}
|
|
}
|