1797 Commits

Author SHA1 Message Date
end-4 df0c7bbbd6 Update rules.conf 2025-11-12 21:49:12 +01:00
end-4 7bfbf011d2 taskbar: middle click to launch new instance 2025-11-12 21:40:21 +01:00
end-4 945c6a0782 wbar: add tooltip and stuff 2025-11-12 21:38:30 +01:00
end-4 20cae142d7 fix widget button when on the left 2025-11-12 00:16:32 +01:00
end-4 20e1f0e0bb taskbar: window previews 2025-11-12 00:09:22 +01:00
end-4 a412688af2 add bg, taskbar items 2025-11-11 20:23:09 +01:00
end-4 dec65aea17 update hyprland config 2025-11-11 00:03:19 +01:00
end-4 cbcb8cf8e1 wbar: more interactions 2025-11-11 00:01:57 +01:00
end-4 fdcb95b8a4 wbar: add widgets, taskview, light theme 2025-11-10 23:41:15 +01:00
end-4 694eaccfbf add start and search icons 2025-11-10 22:48:04 +01:00
end-4 42919c59ec wbar: add volume and battery icons 2025-11-10 21:36:08 +01:00
end-4 58980959aa init waffles 2025-11-10 20:45:38 +01:00
clsty f98c422254 Comment hyprctl reload (#2427 #2200) 2025-11-10 21:20:48 +08:00
clsty 1cfeff8b10 Improve 3.files-legacy.sh 2025-11-10 21:14:23 +08:00
clsty 3cc68b29da Improve format in install-deps 2025-11-10 20:34:07 +08:00
clsty 3b212c454d Update setups.sh 2025-11-10 20:30:07 +08:00
clsty b5ddc36d5e Improve dist-determine.sh 2025-11-10 19:45:36 +08:00
Celestial.y 38586f0efc Re-add version lock for quickshell-git. (#2414) 2025-11-10 19:23:55 +08:00
clsty 0462ee5e56 Fix versionlock position 2025-11-10 19:18:31 +08:00
clsty 711fb48e37 Improve handle deprecated deps logic (#2425) 2025-11-10 18:32:54 +08:00
Celestial.y 6d4ea704d6 fix: Remove deprecated hyprland-qtutils package (#2424) 2025-11-10 16:16:27 +08:00
dancincomrade 39ed0e472a fix: remove deprecated hyprland-qtutils package as part of install script 2025-11-10 15:32:53 +08:00
Celestial.y a54a8d8daf Gentoo Updates (#2371) 2025-11-10 14:51:31 +08:00
jwihardi 80d62c438f Merge pull request #5 from jwihardi/gentoo-support
Gentoo support
2025-11-10 01:26:11 -05:00
jwihardi 61b89de945 deleted setup and modified .local chown 2025-11-10 01:23:28 -05:00
jwihardi c812e9c8af forgot backlash 2025-11-10 00:53:07 -05:00
Celestial.y d001bc1269 Add a TODO in 1-issue.yml 2025-11-10 11:25:18 +08:00
clsty 98d2c4f881 Introduce OS_GROUP_ID 2025-11-10 10:38:14 +08:00
jwihardi 4396079c28 added chown for .local 2025-11-09 20:47:27 -05:00
jwihardi e10ad1ed71 updated setup, don't need chown 2025-11-09 20:37:42 -05:00
clsty 051accbe2f Update dist-gentoo/README 2025-11-10 09:05:31 +08:00
clsty 74941d15bf Not use setups-selector but 2.setups.sh 2025-11-10 08:56:07 +08:00
jwihardi cf1ea9e3d9 updated useflags to not be live for hypr stuff 2025-11-09 19:01:36 -05:00
jwihardi 3dd1264a12 removed hyprland custom ebuilds - part 2 2025-11-09 19:00:12 -05:00
jwihardi dbb8d015e8 removed hyprland custom ebuilds 2025-11-09 18:57:56 -05:00
jwihardi 13892a01e1 added quickshell dependencies 2025-11-09 18:49:58 -05:00
end-4 fb7dbaa187 add missing dock loading extra condition 2025-11-09 23:33:39 +01:00
end-4 2c4668bcb0 move panel enable/disable to config 2025-11-09 23:31:51 +01:00
jwihardi d0e2c69de3 Merge branch 'end-4:main' into main 2025-11-09 17:16:12 -05:00
jwihardi 3a64eae028 added adw-gtk3 keyword 2025-11-09 17:15:35 -05:00
Celestial.y 284bb084c6 Update pkgrel in PKGBUILD 2025-11-10 01:49:49 +08:00
end-4 14c115f80a background: add option to only show clock when locked (#2387) 2025-11-09 13:57:29 +01:00
end-4 8b5a790d54 increase overlay clickthru opacity, disable cheatsheet split btns 2025-11-09 13:14:25 +01:00
end-4 e6a19a6afb format 2025-11-09 13:13:47 +01:00
end-4 781af1d420 fix some unqualified access 2025-11-09 13:13:43 +01:00
end-4 baa3c2a773 overlay: add kurukuru 2025-11-09 12:58:48 +01:00
end-4 8f4190a939 overlay: refractor widget background 2025-11-09 12:58:10 +01:00
end-4 696ff4298f BooruImage: refractor image downloader proc 2025-11-09 12:57:05 +01:00
end-4 f2462eb1b4 overlay: add battery level 2025-11-09 11:12:18 +01:00
end-4 53768a6885 qs: move panels into modules/ii 2025-11-09 08:58:56 +01:00
ririko6z 5db16e6245 Merge branch 'end-4:main' into fedora 2025-11-09 13:58:35 +08:00
Elysia dda0a228cf Re-add version lock. 2025-11-09 13:47:41 +08:00
Celestial.y f678a55e6a fix: Change quickshell-git and hyprland-qt-support to local builds. (#2412) 2025-11-09 13:31:21 +08:00
Elysia b322af7051 Fixed a minor issue 2025-11-09 13:07:35 +08:00
Elysia 7236d2f50b revision. 2025-11-09 12:39:16 +08:00
Elysia 87f5bc5870 Change hyprland-qt-support to local build 2025-11-09 12:33:38 +08:00
Elysia 3187239175 Change quickshell-git to local build 2025-11-09 12:33:17 +08:00
jwihardi 09fd61c71d added roboto-flex dependency 2025-11-08 23:07:51 -05:00
jwihardi c1f84c77dd roboto-flex font 2025-11-08 22:22:32 -05:00
jwihardi 3f242fa298 Merge branch 'end-4:main' into main 2025-11-08 22:18:05 -05:00
clsty c7ac7b5b43 Improve deps-selector 2025-11-09 09:31:15 +08:00
Celestial.y 688a36af58 Improve issue template 2025-11-09 08:33:41 +08:00
Celestial.y 10e1509d5d fix fedora install-deps crashing on hyprland-qt-support step (#2406) 2025-11-09 07:38:43 +08:00
end-4 fc2e51ebbc cheatsheet: use w11 icon for super key by default 2025-11-09 00:05:12 +01:00
end-4 1433fb5412 fix weird volume dialog spacing 2025-11-09 00:00:49 +01:00
end-4 b383635fa8 overlay: fix weird fade 2025-11-08 23:53:51 +01:00
end-4 788c01c242 overlay: make widgets resizable 2025-11-08 23:50:21 +01:00
Jacky b965b50009 fix fedora install-deps crashing on hyprland-qt-support step
fix a missing v function invocation that leads to a crash if the hyprland-qt-support package is already installed
2025-11-08 23:19:20 +01:00
clsty 241f33fb2f Post-PR revision on dist-fedora 2025-11-09 02:24:36 +08:00
clsty f9bc4b1608 Fix dist-fedora setups.sh from modify repo 2025-11-09 02:15:02 +08:00
Celestial.y 0091fce2c1 Provide Fedora support (#2393) 2025-11-09 02:00:50 +08:00
Elysia cf43479530 Dynamically control the version of quickshell. 2025-11-09 01:29:48 +08:00
end-4 d74e385f84 fix undefined warning 2025-11-08 17:26:37 +01:00
end-4 d292a85a5e wallpaper selector: fix file:// being passed to magick script 2025-11-08 17:01:54 +01:00
end-4 3b1d8fd262 make volume device selection use a combobox 2025-11-08 16:48:00 +01:00
end-4 769ed3bf71 fix clock alignment in lock screen (fix #2399) 2025-11-08 14:04:16 +01:00
Celestial.y d10ac9cc74 Update comment 2025-11-08 20:15:46 +08:00
end-4 4bf31544e7 Turkish language support (#2396) 2025-11-08 09:42:42 +01:00
ririko6z 03a149c10e Merge branch 'end-4:main' into fedora 2025-11-08 13:47:13 +08:00
Elysia 5ec8cca5d5 Update README.md 2025-11-08 13:40:02 +08:00
Elysia 44c8de82c7 Adjust the code structure. 2025-11-08 13:39:25 +08:00
Elysia b08a545ece Use a locally built RPM instead of directly modifying it. 2025-11-08 10:48:23 +08:00
Pico 42b9c7c854 added Turkish language support 2025-11-08 03:48:28 +03:00
end-4 994985ecae overlay: recorder: make open folder button work with custom path 2025-11-07 22:13:56 +01:00
end-4 229c9d5e78 overlay: adjust titlebar spacing 2025-11-07 21:50:13 +01:00
end-4 ae52e28afb overlay: adjust default crosshair position 2025-11-07 21:35:50 +01:00
end-4 758d40fc8b overlay: adjust volume mixer padding 2025-11-07 21:33:54 +01:00
jwihardi 601cb3ffbe Merge branch 'end-4:main' into main 2025-11-07 15:32:13 -05:00
jwihardi 9aa869af77 updated hyprland to not use live ebuild 2025-11-07 15:31:48 -05:00
end-4 1d07260fd0 add kb focus border for group buttons 2025-11-07 21:24:37 +01:00
jwihardi fe06c1891f added qt unmasks and keywords 2025-11-07 15:21:22 -05:00
end-4 26f2a9f3fd fix more null warnings 2025-11-07 21:11:11 +01:00
end-4 1cc04e118f overlay: hide some unnecessary buttons 2025-11-07 21:10:21 +01:00
end-4 87181585aa overlay: add config option for clickthrough widget opacity 2025-11-07 21:09:39 +01:00
end-4 a831d393c1 fix some undefined warnings 2025-11-07 21:08:30 +01:00
end-4 1845e59090 Feature (Overlay): MangoHud Fps Limiter widget (#2388) 2025-11-07 21:06:55 +01:00
end-4 3fe8377309 make timer restart instead of start 2025-11-07 21:06:31 +01:00
end-4 20b3d2498e overlay: add delay to focus grab 2025-11-07 21:05:59 +01:00
end-4 917fae6d4f overlay: fps limiter: adjust default position 2025-11-07 20:54:23 +01:00
end-4 a91fe7db30 overlay: fps limiter: use enums for states 2025-11-07 20:49:48 +01:00
end-4 daa4dd7b0f overlay: fps limiter: fix weird container and button size 2025-11-07 20:33:54 +01:00
end-4 cd952729f4 overlay: adjust titlebar-content gap 2025-11-07 18:45:42 +01:00
end-4 843025bc64 overlay: make volume mixer has both output and input 2025-11-07 18:33:32 +01:00
reakjra 40368432e8 Merge branch 'main' into featOverlay/MangoHud-Fps-Limiter 2025-11-07 18:30:42 +01:00
end-4 2c88a71eed overlay: make widgets have proper round corners when pinned 2025-11-07 18:21:59 +01:00
Celestial.y 082f12084d Fix #2200 2025-11-07 23:59:20 +08:00
reakjra 23b471edc2 Fix non-sensical logic, timers and animations. 2025-11-07 16:34:29 +01:00
reakjra e50ea627e8 Fix non-sensical logic, timers and animations. 2025-11-07 16:28:45 +01:00
Celestial.y fd8f569477 Add comment (#2220) 2025-11-07 22:27:44 +08:00
end-4 1766375348 fix weird max cpu freq 2025-11-07 14:00:17 +01:00
Elysia 1a58f1258a Provide Fedora support 2025-11-07 20:40:12 +08:00
end-4 0f867df271 overlay: better default positions 2025-11-07 13:02:34 +01:00
end-4 a27a6deddf overlay: add resource monitor widget 2025-11-07 12:56:44 +01:00
end-4 e5e85db75d refractor secondary tab bar 2025-11-07 12:56:08 +01:00
end-4 96cda9e6dd Customizable keybind display options to Cheatsheet (#2338) 2025-11-07 09:52:25 +01:00
jwihardi fe3c502459 updated ebuilds + licenses 2025-11-07 02:08:40 -05:00
jwihardi e2799414dd Merge branch 'end-4:main' into main 2025-11-07 01:28:10 -05:00
jwihardi fa08f972d6 use new ebuilds 2025-11-07 01:27:45 -05:00
Madjid Taha b06a7ce58e fix merge 2025-11-07 02:42:51 +01:00
clsty a0c5940a94 Use "Han chars" 2025-11-07 06:08:46 +08:00
end-4 3365719a49 tray menu: fix weird popin anim origin point 2025-11-06 23:07:50 +01:00
end-4 6afe810d69 batterypopup: move health to below energy rate 2025-11-06 23:04:42 +01:00
end-4 bf70be7f4a overlay: add recorder widget 2025-11-06 23:02:21 +01:00
end-4 1a4b4b8bef use ipc calls more for compatibility 2025-11-06 22:59:09 +01:00
reakjra 7f49daf422 undo personal edits by mistake 2025-11-06 22:44:40 +01:00
reakjra f4c32f89f2 Added proposed fixes and implemented some animations+error text 2025-11-06 22:41:14 +01:00
end-4 2807bed255 Save paths for screen recording and screenshots (#2354) 2025-11-06 21:56:13 +01:00
end-4 e5e598853f japanese borrows chinese chars... 2025-11-06 21:49:03 +01:00
vaguesyntax 47aa8232f7 fixes 2025-11-06 23:39:32 +03:00
end-4 06c51553ba refractor bar tooltips 2025-11-06 21:35:31 +01:00
end-4 281646ef0c Add battery health to battery popup (#2355) 2025-11-06 21:15:04 +01:00
end-4 2f1c66570f Change battery health icon from 'healing' to 'heart_check' 2025-11-06 21:14:51 +01:00
reakjra 60144ca3de Feature (Overlay): MangoHud Fps Limiter widget 2025-11-06 14:23:13 +01:00
Madjid Taha a0131e5bf8 fix: use end-4 copy in InterfaceConfig 2025-11-06 12:33:29 +01:00
Madjid Taha 4afaa7cc7e Merge branch 'main' into keybinds-settings 2025-11-06 12:30:05 +01:00
end-4 ad9f25c346 weather widget: make number and icon further apart 2025-11-06 11:08:14 +01:00
end-4 6be3fe0c65 overlay: add option for zoom anim and darkening surface 2025-11-06 10:55:33 +01:00
end-4 3bebabd95e settings: extend japenis/roman ws numbers 2025-11-06 10:54:00 +01:00
end-4 6e9f2c14ce clarify overlay widget instructions a bit 2025-11-06 10:38:35 +01:00
end-4 4f68e9e61a add overlay 2025-11-06 10:29:59 +01:00
end-4 56a7e8cbdd right sidebar: refractor volume mixer dialog content 2025-11-06 10:25:45 +01:00
clsty 25a63b593d Fix gh action 2025-11-06 16:56:22 +08:00
clsty 32af8bf257 Fix gh action 2025-11-06 16:49:54 +08:00
end-4 cd0d49032a readme: add warning for noobs 2025-11-05 15:37:44 +01:00
clsty 11f7adc643 Update swaylock color in vianix/hypridle.conf 2025-11-05 21:12:16 +08:00
clsty 6d6fa42857 Move ar/conf.d to ar/fonts.conf (#2384) 2025-11-05 19:34:56 +08:00
clsty d14d170016 Update dist-nix/README 2025-11-05 19:34:03 +08:00
clsty bd04346f16 Enable fontconfig in home.nix (#2384) 2025-11-05 19:31:35 +08:00
end-4 46bd7c785a Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-11-05 12:23:50 +01:00
end-4 520068e523 rename font config file (#2384) 2025-11-05 12:23:44 +01:00
clsty 902c8327d3 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-11-05 19:19:14 +08:00
clsty d497e00474 Update dist-nix/README 2025-11-05 19:18:47 +08:00
end-4 b5e1bcf3be Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-11-05 12:13:53 +01:00
end-4 923841cb56 region selector: add selection padding to target regions 2025-11-05 12:13:46 +01:00
end-4 6ca5175bb0 silent some stupid prints 2025-11-05 12:13:13 +01:00
clsty 9aa6d03f87 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-11-05 18:51:27 +08:00
clsty eff52332b5 Update dist-nix/README 2025-11-05 18:51:09 +08:00
end-4 bf376c8aaa make clock closer to quote 2025-11-05 11:46:52 +01:00
end-4 64f6081b14 config: move quote settings to clock widget subsection 2025-11-05 10:23:20 +01:00
end-4 b3f81f350c reduce persistent low battery warnings 2025-11-05 10:16:08 +01:00
end-4 025a819b63 scale up bg widgets when dragging 2025-11-05 10:15:21 +01:00
end-4 2667751a1c add settings entries for bg widgets 2025-11-05 10:15:06 +01:00
end-4 b1007f2ded make abstractwidget's cursor shape more accurate 2025-11-05 10:14:36 +01:00
end-4 aca19d6903 adjust weather widget size 2025-11-05 10:14:17 +01:00
end-4 52dced17a3 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-11-05 08:52:18 +01:00
clsty a1606c9c23 Update comment 2025-11-05 13:47:09 +08:00
jwihardi 9249034fa6 Merge branch 'end-4:main' into main 2025-11-05 00:06:43 -05:00
jwihardi 1924111d6b added some font ebuilds 2025-11-05 00:06:08 -05:00
clsty 8214e2d052 Update dist-nix/install-deps.sh 2025-11-05 12:17:43 +08:00
clsty 564fd54cdb Update dist-nix (improve install via system PM) 2025-11-05 11:51:47 +08:00
clsty a92bd67957 Update flake.lock 2025-11-05 10:44:48 +08:00
clsty 22469dc5f2 Update dist-nix (use unstable nixpkgs) 2025-11-05 10:40:08 +08:00
clsty 5f4f8980f0 Move Qt deps into Quickshell PKGBUILD 2025-11-05 10:24:21 +08:00
clsty e24630b9be Use qt6 and NixGL wrapper for quickshell 2025-11-05 08:40:05 +08:00
clsty 51076dda88 Update TODO 2025-11-05 07:55:22 +08:00
end-4 37244dc0f7 background: add weather widget
Co-Authored-By: Vague Syntax <173799252+vaguesyntax@users.noreply.github.com>
2025-11-05 00:44:22 +01:00
end-4 c82a2e835b move weather icons to Icons
Co-Authored-By: Vague Syntax <173799252+vaguesyntax@users.noreply.github.com>
2025-11-05 00:43:19 +01:00
end-4 8a35609b0d refractor StyledDropShadow 2025-11-05 00:41:44 +01:00
end-4 1f208125bf remove clock scale option (it has never been good) 2025-11-05 00:41:28 +01:00
end-4 ba6fba447a fix some undefined warnings 2025-11-05 00:40:34 +01:00
clsty c19766c887 Updpate flake.lock 2025-11-05 07:31:04 +08:00
end-4 0e7422c335 make bg clock draggable 2025-11-05 00:07:38 +01:00
end-4 67695c8edb Update OverviewWidget.qml 2025-11-04 22:52:48 +01:00
Madjid Taha ede86dc7a7 fix(cheatsheet): change config keys 2025-11-04 20:55:34 +01:00
Madjid Taha a28945f3ec fix: remove warning unqualified access 2025-11-04 17:51:20 +01:00
Madjid Taha 80275c5adf Merge branch 'end-4:main' into keybinds-settings 2025-11-04 17:21:27 +01:00
EinBowser 31f2184dc6 Removed settings and configs for battery health 2025-11-04 15:58:01 +01:00
end-4 9d830767c7 lock: fix wrong password shake fricks up text field placement (#2368) 2025-11-04 15:10:55 +01:00
end-4 9471223a76 nuke primarytab 2025-11-04 15:08:08 +01:00
end-4 c2942afe8e make regionselection kb focus ondemand 2025-11-04 15:07:44 +01:00
end-4 d8adcce5fb fix(lock): extra checks for fingerprint (#2370) 2025-11-04 15:06:25 +01:00
end-4 b9a7fa4d0d Try kebab over underscores for app icons (#2361) 2025-11-04 15:05:32 +01:00
end-4 7f8265c9e6 auto color scheme: dont use "content" 2025-11-04 14:47:14 +01:00
EinBowser c1ff57c3d0 Don't display when unsupported 2025-11-04 14:20:23 +01:00
clsty 4cad276963 Try fix Hyprland 2025-11-04 21:10:56 +08:00
clsty 5a4b4e6d3c Fix VIANIX 2025-11-04 20:58:46 +08:00
clsty 7440f78069 Update TODO 2025-11-04 20:54:14 +08:00
clsty 38cd1a7169 Update dist-nix 2025-11-04 20:47:35 +08:00
clsty 4443b736d8 Add pkg-config for nix 2025-11-04 15:57:44 +08:00
clsty d509a8777b Update home.nix 2025-11-04 15:47:57 +08:00
clsty 27754e5d03 Update flake.lock 2025-11-04 15:34:41 +08:00
clsty fbb284ae00 Update message in dist-nix 2025-11-04 15:30:54 +08:00
clsty 9bbabc3079 Tweak order of deps in PKGBUILD 2025-11-04 15:23:41 +08:00
clsty 5a3abbe45a Remove non-needed deps in dist-nix 2025-11-04 15:10:03 +08:00
clsty e5283cac5c Remove non-needed deps from dist-arch 2025-11-04 14:59:08 +08:00
clsty eb55f2533d Update dist-nix 2025-11-04 14:54:12 +08:00
jwihardi 352e459d82 Merge pull request #4 from jwihardi/songrec
Songrec
2025-11-04 01:23:29 -05:00
jwihardi 90a4e2128b fixed spacing 2025-11-04 01:20:03 -05:00
jwihardi c79a3e6309 Merge branch 'end-4:main' into songrec 2025-11-04 01:18:17 -05:00
jwihardi a6f1560bce added songrec 2025-11-04 01:17:33 -05:00
clsty a60f917f59 Apply NixGL to quickshell 2025-11-04 13:48:09 +08:00
clsty 0f93784b8a Fix quickshell in dist-nix 2025-11-04 12:40:38 +08:00
clsty 5af7420129 Update dist-nix 2025-11-04 12:33:48 +08:00
clsty 17d2d32bf1 Update dist-nix 2025-11-04 11:45:34 +08:00
clsty 7534509caa Support custom os-release 2025-11-04 11:33:54 +08:00
clsty 76db90af1b Update flake.nix 2025-11-04 11:15:53 +08:00
clsty b4b15a2808 Update home.nix 2025-11-04 10:22:28 +08:00
0blivi0nis f2055d128e fix(lock): extra checks for fingerprint 2025-11-03 17:04:39 -08:00
clsty 534ef6fd7c Add ii_check_PKGBUILD_version() in diagnose 2025-11-04 08:59:40 +08:00
clsty 4cb2c6589d Update home.nix 2025-11-04 07:36:45 +08:00
end-4 f23e9e5da9 antiflashbang: add dedicated toggle, make disabling also restore brightness 2025-11-03 21:48:26 +01:00
end-4 22fb48cd0a overview: add allow not centering icons 2025-11-03 21:36:12 +01:00
end-4 3ae87c8a67 cheatsheet: make more compact 2025-11-03 21:28:35 +01:00
end-4 5d773090eb sidebar: make quick toggle behave more similar to on android 2025-11-03 21:22:05 +01:00
EinBowser c0d64c4630 Forgot to delete unnecessary import 2025-11-03 20:55:17 +01:00
EinBowser a323e32a42 Removed helper script and made workaround in qml 2025-11-03 20:53:40 +01:00
end-4 1703cb24d1 fix left sidebar weird color when detached and transparency enabled 2025-11-03 20:33:03 +01:00
end-4 35ce444c23 right sidebar: fix no alt action toggle not very readable when enabled 2025-11-03 20:08:53 +01:00
clsty 8b2f1c054c Merge remote-tracking branch 'refs/remotes/origin/main' 2025-11-04 01:49:06 +08:00
clsty 56c43aa1e6 Update dist-nix 2025-11-04 01:48:46 +08:00
end-4 2cd705950f readme: update left sidebar screenshot 2025-11-03 18:47:48 +01:00
end-4 467b84d3e2 left sidebar: make content containerized 2025-11-03 18:30:11 +01:00
end-4 4270d2fe56 region selector: make mode selection animated 2025-11-03 18:27:47 +01:00
end-4 519de4f5ba cheatsheet: use toolbar tabbar 2025-11-03 18:11:17 +01:00
end-4 90a6efecbb fix toolbar tabbar undefined warnings 2025-11-03 18:10:39 +01:00
clsty 27e3fd5e13 Remove install-agsv1(); Update home.nix 2025-11-04 00:59:15 +08:00
clsty e55d70fa62 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-11-04 00:45:19 +08:00
clsty b873a1f033 Update home.nix 2025-11-04 00:45:00 +08:00
end-4 0f0bc9d318 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-11-03 17:00:34 +01:00
end-4 087a736d1a left sidebar: toolbar-style tabs 2025-11-03 17:00:28 +01:00
clsty 97fbec551f Tweak indents in PKGBUILDs 2025-11-03 23:58:51 +08:00
end-4 7c974b7fb4 wallpaper selector: adjust quick dir button appearance 2025-11-03 16:55:16 +01:00
end-4 4f712116c2 adjust IconAndTextToolbarButton spacing 2025-11-03 16:54:47 +01:00
end-4 83ce5f3fea refractor animated index pair in workspaces 2025-11-03 16:54:23 +01:00
end-4 7f4a626a83 background: make digital clock quote not italic 2025-11-03 16:54:05 +01:00
clsty 47810c95da Tweak geoclue for via-nix 2025-11-03 23:48:07 +08:00
clsty bd14c73f9b Add vianix-warning() 2025-11-03 20:38:49 +08:00
clsty f368382765 vianix: Install fish instead of zsh 2025-11-03 20:25:23 +08:00
end-4 efd44c421b Limit booru calls for tags to 10 (#2362) 2025-11-03 13:11:27 +01:00
clsty d429d55d16 Prepare for --via-nix fallback to swaylock 2025-11-03 19:58:35 +08:00
André Zanghelini e3fc712e11 Limit booru calls for tags to 10 2025-11-03 01:38:41 -03:00
André Zanghelini f5b495969b try kebab over underscores for app icons 2025-11-03 01:03:58 -03:00
end-4 1ee08fca51 keyringstorage: properly handle keyring fetching (#2108)
- if auto lock enabled, don't do anything and wait for lock password
- not try to overwrite and don't consider loaded when unlocking fails
- retry unlock and re fetch on demand (ai request)
2025-11-02 23:20:01 +01:00
end-4 525108dd95 fix weird blur xray on media controls 2025-11-02 21:49:27 +01:00
end-4 d005f9204c make volume inc keybind more idiot proof 2025-11-02 19:46:31 +01:00
Madjid Taha 6237e117aa Merge branch 'end-4:main' into keybinds-settings 2025-11-02 17:28:40 +01:00
Madjid Taha 0c29167057 try something for the nyx-4 feedback 2025-11-02 17:23:31 +01:00
end-4 e28550b53f add missing animations to android toggles 2025-11-02 08:59:33 +01:00
end-4 c43e163a56 adjust font axes 2025-11-02 08:59:19 +01:00
clsty 31f40ae9ee Update diagnose 2025-11-02 13:21:56 +08:00
end-4 b8051ce2cf make bg clock color match pixel more 2025-11-02 01:07:42 +01:00
end-4 09c637914d use (tweaked) roboto flex for shell text 2025-11-02 00:57:50 +01:00
Madjid Taha 7e283404f3 Merge branch 'end-4:main' into keybinds-settings 2025-11-02 00:40:59 +01:00
EinBowser 8a20824266 Disabled by default 2025-11-01 23:32:08 +01:00
EinBowser 0e63e698f2 Wrong position and forgot an import 2025-11-01 23:26:36 +01:00
EinBowser c2bb57f0bc Merge branch 'end-4:main' into main 2025-11-01 22:50:21 +01:00
EinBowser 6676d5844b changed the script to the right name, added some info and removed unnecesary debug 2025-11-01 22:22:58 +01:00
EinBowser ca7d6c8ae0 Added config toggle to settings 2025-11-01 22:11:39 +01:00
EinBowser b267b74e8b Added battery health and made it configurable 2025-11-01 20:50:39 +01:00
end-4 dcc14a565d adjust urgent notif color 2025-11-01 20:16:22 +01:00
end-4 f96e84ff4a make polkit dialog icon more readable 2025-11-01 20:13:46 +01:00
end-4 41e9c00fa8 fix weird popup blur xray 2025-11-01 20:11:53 +01:00
end-4 85e3fd5e36 fix weird polkit layer anim 2025-11-01 20:11:38 +01:00
end-4 daf7d2c9dc overview: animate search area 2025-11-01 18:43:02 +01:00
end-4 f663837c4e overview: fix focus func conflict with default prop name 2025-11-01 18:32:02 +01:00
end-4 77d9b93887 overview: more rounding 2025-11-01 18:28:25 +01:00
end-4 816d2b8a76 overview: make search highlight more vibrant 2025-11-01 18:27:57 +01:00
Madjid Taha f40cf790af Merge branch 'end-4:main' into keybinds-settings 2025-11-01 16:07:39 +01:00
Vague Syntax 8e1a3d26b1 Update dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml
Co-authored-by: Madjid Taha <1833954+madjidtaha@users.noreply.github.com>
2025-11-01 17:56:38 +03:00
vaguesyntax a240329f22 fix: initialize recording path setting properly 2025-11-01 16:18:02 +03:00
vaguesyntax 6afa6d2142 remove reduntant code 2025-11-01 16:04:04 +03:00
vaguesyntax 0c587415ea tweaks in settings/config 2025-11-01 16:00:32 +03:00
vaguesyntax ace8802480 add screenshot location 2025-11-01 15:55:46 +03:00
Celestial.y 7e1637b810 Fix image path in README.md 2025-11-01 20:47:32 +08:00
vaguesyntax 0fabedb0c4 tweaks in script 2025-11-01 14:41:29 +03:00
vaguesyntax e567f06cef initial commit of record-location 2025-11-01 14:38:16 +03:00
end-4 bf87ed69ce new default wallpaper 2025-11-01 11:40:31 +01:00
end-4 7cb0e4e039 change dark mode button icon to be less confusing 2025-11-01 11:39:36 +01:00
Madjid Taha 510f1b2188 Merge branch 'end-4:main' into keybinds-settings 2025-11-01 04:19:18 +01:00
clsty 1bea1e8c91 Update comment 2025-11-01 10:35:33 +08:00
clsty 9c89099cf1 Update comment in files-exp 2025-11-01 10:18:52 +08:00
clsty efae444942 Update files-exp 2025-11-01 10:16:45 +08:00
clsty 3536e54b50 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-11-01 10:00:35 +08:00
clsty 17984c812f Update files-exp; Rename 3.files.yaml to 3.files-exp.yaml 2025-11-01 09:52:34 +08:00
Celestial.y 09ad926642 Update comment 2025-11-01 09:46:27 +08:00
clsty e3549e639e Update comment 2025-11-01 09:38:47 +08:00
clsty b421691734 Update comment 2025-11-01 09:22:03 +08:00
clsty 835c113416 Move README.md into .github 2025-11-01 08:09:51 +08:00
clsty 2e807806ba Merge remote-tracking branch 'refs/remotes/origin/main' 2025-11-01 01:25:02 +08:00
clsty 2c21eccac3 Update showhelp 2025-11-01 01:22:52 +08:00
end-4 f302da1275 live light/dark switching for gtk4 2025-10-31 18:17:58 +01:00
clsty 82ce9b866f Update showhelp 2025-11-01 01:09:42 +08:00
clsty df23d79e04 Fix outdate detect 2025-11-01 00:47:00 +08:00
clsty 43aae4ee56 Minor update about git_submodule() 2025-10-31 23:07:35 +08:00
clsty 73be5c5f0a Improve message for backup configs 2025-10-31 22:42:16 +08:00
clsty 02c71e9310 Fix submodule update detect logic 2025-10-31 22:40:43 +08:00
clsty f041272302 Detect cmds in checkdeps 2025-10-31 22:38:00 +08:00
Madjid Taha aeb1955947 end-4 feedback 2025-10-31 14:49:07 +01:00
Madjid Taha a0332cb0df add reference to nerdfonts symbol cheat sheet 2025-10-31 14:49:07 +01:00
Madjid Taha 79df7bbeef add google (assistant, chrome, android) keys 2025-10-31 14:49:07 +01:00
Madjid Taha af64052e33 remove super directly override 2025-10-31 14:49:07 +01:00
Madjid Taha fc479c3582 clean some values 2025-10-31 14:49:07 +01:00
Madjid Taha 886e16a1cf add comment and bring back some value 2025-10-31 14:49:07 +01:00
Madjid Taha 367b1b9499 fix keySubstitutions 2025-10-31 14:49:07 +01:00
Madjid Taha c61da40f70 new symbol map 2025-10-31 14:49:07 +01:00
Madjid Taha 90cc63e57a checkbox on tooltip 2025-10-31 14:49:07 +01:00
Madjid Taha fc17f23533 fix typo 2025-10-31 14:49:07 +01:00
Madjid Taha 69fc9d9b35 fix comment pixelSize key 2025-10-31 14:49:07 +01:00
Madjid Taha 533156e0d0 cheatsheet add font size setting and macos like shortcut 2025-10-31 14:49:07 +01:00
Madjid Taha 8c125cccb1 add other symbols 2025-10-31 14:49:07 +01:00
Madjid Taha 3da64f6bc5 fix useMouseSymbol boolean typo 2025-10-31 14:49:07 +01:00
Madjid Taha daa671c6a5 feat: add custom super key icon, mac symbol for mods keys and icon for function keys 2025-10-31 14:49:07 +01:00
end-4 71eb88016e overview: correct💢 the search field's height 2025-10-31 12:13:02 +01:00
end-4 c45166387b Improve music recognition script source management (#2344) 2025-10-31 12:03:47 +01:00
end-4 f4dffe7f37 Merge branch 'main' into patch-2 2025-10-31 11:28:45 +01:00
end-4 df69162f78 deps: add songrec 2025-10-31 11:23:34 +01:00
end-4 e14c9b61d5 fix music recognition script 2025-10-31 10:10:25 +01:00
end-4 b1cc6bd19b overview: fix search bar blur 2025-10-31 09:19:33 +01:00
Celestial.y e02b505ae5 Update feature request template 2025-10-31 13:18:34 +08:00
Celestial.y 6aad5a9581 Update issue template 2025-10-31 13:17:35 +08:00
Yosuke Nishiyama 4b33a10779 Improve music recognition script source management
Refactor source type handling and validation checks.
2025-10-31 04:55:56 +00:00
Celestial.y 6ec202da9e Update command from ags to qs
Can't belive it existed till now and no one ever noticed that.
2025-10-31 09:30:43 +08:00
clsty 54cf1cf821 Update quickshell version for Gentoo 2025-10-31 09:15:42 +08:00
clsty d36966e2d7 Still deprecate install.sh and update.sh anyway; Tidier structure 2025-10-31 09:11:03 +08:00
clsty f01a2a06b5 Fix 3.files-exp.sh; Improve structure 2025-10-31 08:47:41 +08:00
clsty f866ef1fd7 Improve backup functions; Minor fix for checkdeps 2025-10-31 08:30:41 +08:00
end-4 480966f978 overview: add music recognition button to search bar 2025-10-30 23:08:30 +01:00
end-4 b3f06049be add more notif icon 2025-10-30 23:07:27 +01:00
end-4 7887805550 format 2025-10-30 23:07:09 +01:00
end-4 dbd12d3e92 overview: fancier search bar 2025-10-30 22:20:06 +01:00
end-4 db79ecd636 polkit: make sec to dismiss work properly 2025-10-30 22:17:56 +01:00
end-4 9da8cc0cea update quickshell version for polkit 2025-10-30 19:38:26 +01:00
end-4 f9c7bbbe01 quickshell polkit agent 2025-10-30 19:37:28 +01:00
end-4 81116598cb sidebar: ai: make loading indicator transition smoother, disable text fade by default 2025-10-30 18:17:57 +01:00
end-4 46c803c9ce sidebar: add loading indicator for ai 2025-10-30 18:13:27 +01:00
end-4 93567a68e8 Weather settings in settings app (#2337) 2025-10-30 17:23:17 +01:00
clsty 2294653431 Add deps to dist-nix 2025-10-30 23:34:36 +08:00
vaguesyntax aae3add0c9 change settings text 2025-10-30 18:25:48 +03:00
vaguesyntax b690cd6335 Merge branch 'main' into weather-settings 2025-10-30 18:13:49 +03:00
vaguesyntax 487c0fc916 initial commit of weather settings 2025-10-30 18:10:37 +03:00
end-4 0551c010b5 fix clock hands rotating in the wrong direction 2025-10-30 16:04:55 +01:00
end-4 d645286744 lock: add setting to toggle new shape password chars 2025-10-30 15:56:17 +01:00
end-4 f3e674684e Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-30 15:55:29 +01:00
end-4 fd72cd5e22 add config option to use old sine wave cookie clock 2025-10-30 15:45:26 +01:00
clsty e8d2f8c476 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-10-30 22:43:14 +08:00
clsty e7e25cd25b Update showhelp() 2025-10-30 22:42:56 +08:00
Celestial.y d7750c099b fix(audio): Replace pulseaudio with pipewire-pulseaudio on Arch Linux (#2336) 2025-10-30 22:30:56 +08:00
clsty b74019a83b Merge remote-tracking branch 'refs/remotes/origin/main' 2025-10-30 22:29:11 +08:00
dancincomrade f81f4925a9 chore(audio): increment pkgrel by 1 due to new deps added to PKGBUILD 2025-10-30 22:29:11 +08:00
clsty df307d3d45 Update dist-nix 2025-10-30 22:28:31 +08:00
end-4 a122d6e905 uhh more round 2025-10-30 15:27:14 +01:00
end-4 a97b7706d8 make cookie clock more round 2025-10-30 15:23:58 +01:00
clsty e622928d9d Update dist-nix 2025-10-30 22:18:42 +08:00
clsty fceda9bd35 Rename var 2025-10-30 22:09:09 +08:00
dancincomrade 0bd22f89a7 fix: replace pulseaudio with pipewire-pulseaudio 2025-10-30 22:04:15 +08:00
end-4 1b996e37a7 adjust clock appearance 2025-10-30 12:38:30 +01:00
end-4 403344e120 make materialcookie use rounded polygons 2025-10-30 12:24:10 +01:00
end-4 a200951b75 format 2025-10-30 12:23:45 +01:00
end-4 5c71c53787 make region selector use materialshape instead of materialcookie 2025-10-30 11:42:54 +01:00
end-4 40b1e8297f lock: fix weird hiding anim with floating windows 2025-10-30 11:24:41 +01:00
end-4 dfbbe3fcca lock: make window hiding anim work with floating windows 2025-10-30 11:07:57 +01:00
end-4 b484e3311c use new QtCore import instead of Qt.labs.platform 2025-10-30 11:07:33 +01:00
end-4 287172cd5d update shapes submodule 2025-10-30 11:07:20 +01:00
end-4 5ef979db79 Small animation for quickshell lock (#2304) 2025-10-30 10:02:05 +01:00
end-4 af2dcc8533 Merge branch 'main' into main 2025-10-30 10:00:39 +01:00
end-4 06514ed7b7 lock: simplify shake anim impl 2025-10-30 09:58:52 +01:00
Celestial.y c7bc853ab3 Update nix install-deps.sh 2025-10-30 16:55:44 +08:00
end-4 3f20ab758c feat(lock): add fingerprint support (#2308) 2025-10-30 09:05:49 +01:00
end-4 e3db8372a7 lock: remove useless comment, declare fingerprint check proc running directly 2025-10-30 09:04:58 +01:00
end-4 175379dfdb locksurface: adjust fingerprint icon size/spacing 2025-10-30 09:03:11 +01:00
clsty ae87646e40 Update submodule in exp-update (#2334) 2025-10-30 15:45:49 +08:00
clsty b0f09b20d4 Fix message format 2025-10-30 13:27:26 +08:00
clsty f10bbacf7b Update checkdeps 2025-10-30 12:58:24 +08:00
clsty f50a3fe686 Update checkdeps 2025-10-30 12:57:01 +08:00
clsty bdc55dd082 Update checkdeps 2025-10-30 12:52:16 +08:00
clsty 86a10e9af5 Update checkdeps 2025-10-30 12:50:17 +08:00
clsty e5934c3eed Update checkdeps 2025-10-30 12:47:06 +08:00
clsty dabd8dc136 Update checkdeps 2025-10-30 12:44:27 +08:00
clsty 5509e21759 Update checkdeps 2025-10-30 12:37:05 +08:00
clsty f324310355 Update checkdeps 2025-10-30 12:33:34 +08:00
clsty 8b25e2b037 Update checkdeps 2025-10-30 12:27:19 +08:00
clsty 634fb09d2e Update checkdeps 2025-10-30 12:25:15 +08:00
clsty 0ac39d4356 Add subcmd checkdeps 2025-10-30 12:15:21 +08:00
clsty 60a0dcfdcf No more prompt about how to use ii on AGS 2025-10-30 11:57:58 +08:00
Celestial.y 6551d7cc5e Gentoo added go-yq (#2332) 2025-10-30 11:02:44 +08:00
jwihardi 4859acb700 Merge branch 'end-4:main' into main 2025-10-29 22:43:59 -04:00
jwihardi 34c46910b2 updated version number
wups, removed revision 1
2025-10-29 22:42:23 -04:00
jwihardi d51ce6a46f gentoo added yq-go 2025-10-29 22:35:39 -04:00
clsty bd8daf4015 Update backup logic in 3.files-exp.sh 2025-10-30 09:00:11 +08:00
clsty 649be3741c Add go-yq as dependency 2025-10-30 08:59:33 +08:00
end-4 fcc2ee3551 ai: cleaner message block delegate, add regen button 2025-10-30 00:40:23 +01:00
end-4 128808a56d styledswitch: fix wrong easing type 2025-10-30 00:03:31 +01:00
end-4 714895976f primarytabbar: use synchronizer to simplify bindings 2025-10-30 00:03:18 +01:00
Celestial.y 9fe68c5a38 Add YAML-based file installation system (issue #2137) (#2329) 2025-10-30 06:49:41 +08:00
end-4 a3a62f9826 make vscode theming work with some not-vs-vscode 2025-10-29 23:21:13 +01:00
end-4 389fd5e42c update material shapes for less weird spinny 2025-10-29 23:05:50 +01:00
end-4 947a13556a media controls: make rounding consistent with other panels 2025-10-29 23:05:32 +01:00
end-4 ee1fbf72cc vscode theming with Material Code extension (#2146) 2025-10-29 22:06:53 +01:00
Matt Van Harn 06775806d5 Add YAML-based file installation system (issue #2137)
- Replace hardcoded Bash logic with declarative YAML configuration
- Implement user preference wizard for shell/terminal/keybindings
- Add conditional file copying based on user preferences
- Support multiple sync modes: sync, soft, hard, hard-backup, soft-backup, skip, skip-if-exists
- Implement MD5 hash comparison for idempotent backups
- Add fontconfig fontset support via II_FONTSET_NAME
- Complete coverage of all config directories and files from original script

This is an experimental feature enabled via --exp-files flag.
2025-10-29 15:53:01 -04:00
end-4 961d5e7721 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-29 20:31:22 +01:00
end-4 727227cf8b add option to not animate digital bg clock (closes #2055) 2025-10-29 20:31:14 +01:00
end-4 cead3c87ea fix: prevent volumeChanged recursion (#2320) (#2323) 2025-10-29 20:21:17 +01:00
clsty c550a792b8 Improve backup functions 2025-10-30 00:42:13 +08:00
clsty cc1e5e4636 Improve backup_clashing_targets() 2025-10-29 23:21:31 +08:00
end-4 e279e4d972 make switches more bouncy 2025-10-29 15:59:15 +01:00
end-4 eb6fca6697 fix binding loop in Anime.qml 2025-10-29 15:17:23 +01:00
clsty 7476655302 Fix firstrun logic 2025-10-29 21:52:58 +08:00
雷家兴 8eb50a8917 fix: correctly resume from suspend by waiting pipewire resume (#2320) 2025-10-29 19:26:22 +08:00
end-4 d835d8bc30 adjust button wiggle anim 2025-10-29 12:05:38 +01:00
end-4 981e3be9b0 adjust secondary tab rounding 2025-10-29 12:05:21 +01:00
end-4 db3d8ddfc2 sidebar: corner triggers open only when reaching thru vertical edge 2025-10-29 11:53:12 +01:00
end-4 f5c421ab99 pageplaceholder: rotate less 2025-10-29 11:24:59 +01:00
end-4 4ad001fd9e make notif empty placeholder icon wrapped 2025-10-29 11:24:20 +01:00
end-4 05f3e52f55 make notifs and page placeholder use new material shapes 2025-10-29 11:17:03 +01:00
end-4 8b10ec2cfb sidebar: anime: fix loading indicator showing when navigating w/ keys 2025-10-29 11:04:00 +01:00
clsty 7b278aeff7 Update help 2025-10-29 17:50:12 +08:00
clsty d5e9b20aec Update help 2025-10-29 17:49:28 +08:00
clsty e9c3eca68a Update 3.files.sh about warning_rsync() 2025-10-29 17:44:32 +08:00
Celestial.y 41a328fbf0 Prepend Noto Sans Arabic in fontconfig (#2307) 2025-10-29 17:34:30 +08:00
clsty e1a8ba09f1 Move arabic fontconfig into dots-extra/fontsets/ar 2025-10-29 17:31:01 +08:00
end-4 c565dc1a7e Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-29 10:24:18 +01:00
end-4 ede90eb282 sidebar: anime: pull to load more 2025-10-29 10:24:11 +01:00
clsty f95165185c Implement --fontset (#2307) 2025-10-29 17:23:26 +08:00
end-4 26361718a7 background: only opaque when wallpaper safety triggered 2025-10-29 10:23:14 +01:00
clsty 41cf490681 Update online script url 2025-10-29 17:01:45 +08:00
clsty 44e384a256 Add --core option 2025-10-29 16:09:35 +08:00
clsty 21276f4d1e Improve order of inst scripts 2025-10-29 15:39:18 +08:00
end-4 43e8c85295 Changes with new submodule (#2322) 2025-10-29 08:24:43 +01:00
clsty 4672138b00 Add auto_get_git_submodule() 2025-10-29 08:15:47 +08:00
end-4 b8f115ef10 Merge branch 'Sighthesia-main' 2025-10-28 23:35:26 +01:00
end-4 574cbecf18 Merge branch 'main' of https://github.com/Sighthesia/dots-hyprland into Sighthesia-main 2025-10-28 23:33:56 +01:00
end-4 97b3f7ec55 settings: make right-clicking config file button copy path (#2112) 2025-10-28 22:48:08 +01:00
end-4 7982f43a62 lock: freaking fancy password chars 2025-10-28 22:10:04 +01:00
end-4 fc32ce56d0 booru response: less stupid layout.fillwidth 2025-10-28 22:08:19 +01:00
end-4 6c6a4edf59 shapes submodule 2025-10-28 20:41:04 +01:00
end-4 44da20ed4a settings: reorder servicesconfig sections to be alphabetical 2025-10-28 09:14:08 +01:00
end-4 4f8de83ff4 Music recognition toggle (like Shazam) with SongRec (#2301) 2025-10-28 09:09:26 +01:00
end-4 066971e720 music recognition: adjust message and icon 2025-10-28 09:02:19 +01:00
end-4 107dc8cc24 music recognition: move tmp path to a cleaner place 2025-10-28 08:57:51 +01:00
end-4 7b42efd37a rename music recognition script to be consistent w/ other scripts 2025-10-28 08:52:58 +01:00
end-4 9df78087f0 music recognition: add different icon for microphone source 2025-10-28 08:51:18 +01:00
end-4 06d12fb8ec music recognition: add check for songrec command existence 2025-10-28 08:48:57 +01:00
end-4 08d1a2dfd6 buttongroup: fix childrencount accessing from children 2025-10-27 22:44:33 +01:00
vaguesyntax 035e51b36e add interval to settings, update the script (it was not working as intented) 2025-10-27 20:39:45 +03:00
vaguesyntax 901aa820e5 fix config and icons 2025-10-27 19:33:17 +03:00
end-4 c1a5641ff5 fix wrong minimum brightness (#2310) 2025-10-27 17:32:26 +01:00
end-4 957a63d04a make screenshot to clipboard and file actually copy to clipboard (#2311) 2025-10-27 17:14:59 +01:00
clsty 43960b3a60 Fix outdate_detect() 2025-10-27 23:38:28 +08:00
end-4 8d7e4bdd0d lock: fix duplicate hyprlock spawning 2025-10-27 09:22:19 +01:00
0blivi0nis 9610baf903 🐛 fix(lock): remove duplicate connection, only start if configured, stop on unlock 2025-10-26 23:05:45 -07:00
Celestial.y 52011a7d80 Smart-live-rebuild added to Gentoo (#2309) 2025-10-27 11:10:18 +08:00
jwihardi 6be1437ecc added smart-live-rebuild 2025-10-26 23:05:00 -04:00
z0 cc49b4c921 Updated conf.d 2025-10-27 02:32:40 +03:00
0blivi0nis 3aa1d5f1ed feat(lock): add fingerprint support
Credit to @wooze-pao for providing the required code in #2162
2025-10-26 14:50:50 -07:00
z0 991f113e4e prepend font only if lang is ar 2025-10-27 00:40:27 +03:00
z0 04963a616d remove binding=strong from arabic font prepend 2025-10-27 00:35:23 +03:00
z0 839ca74bf1 Prepend Noto Sans Arabic in fontconfig 2025-10-26 22:00:35 +03:00
Celestial.y 437b2020b7 Update 3.files.sh 2025-10-27 01:09:30 +08:00
Celestial.y 4712931850 Update case in setup 2025-10-26 23:36:40 +08:00
clsty e56af1adc6 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-10-26 23:14:46 +08:00
clsty 7f245e2896 Rearrange sdata/subcmd; add --skip-backup 2025-10-26 23:13:49 +08:00
end-4 4fd5ba5630 add super+shift+r for region record
makes sense cuz other stuff with region selector use super+shift
2025-10-26 15:49:26 +01:00
end-4 7c5740a39b use quickshell region selector for recording 2025-10-26 15:45:07 +01:00
end-4 53998cc51a region selector: fix fab button color 2025-10-26 15:44:48 +01:00
Trung Coder 3faa20a29b Small animation for quickshell lock 2025-10-26 21:22:08 +07:00
clsty 57a2e5aba4 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-10-26 21:55:32 +08:00
clsty ad01fdad4e Improve message about deprecate install.sh and update.sh 2025-10-26 21:54:28 +08:00
Celestial.y 2893dc33b6 Update sdata/README.md 2025-10-26 21:41:53 +08:00
clsty 5a846cdec5 Move sdist/ID to sdata/dist-ID 2025-10-26 21:27:41 +08:00
Celestial.y c13ba5f25e Bump pkgrel from 1 to 2 in PKGBUILD 2025-10-26 21:01:12 +08:00
vaguesyntax 28e956e55c togglable monitor-source 2025-10-26 16:00:49 +03:00
vaguesyntax a05b041d69 fixes and youtube button 2025-10-26 14:12:04 +03:00
vaguesyntax 496225ab9d refactor code 2025-10-26 14:04:52 +03:00
Celestial.y 254b9471e4 Change backup path in environment-variables.sh 2025-10-26 18:40:23 +08:00
vaguesyntax b137feac16 fix: recognized notif not getting pushed 2025-10-26 12:24:35 +03:00
vaguesyntax cf159f6112 some typos 2025-10-26 03:45:43 +03:00
vaguesyntax 60f055f07d initial commit of musicRecognition 2025-10-26 02:46:39 +03:00
end-4 5dd0fe2761 adjust fab icon size and region selector fab color 2025-10-25 10:02:36 +02:00
end-4 43fe3874dd sidebar: make notif delete icon more intuitive 2025-10-25 09:26:07 +02:00
clsty ddf97f79d0 Fix -s for exp-update 2025-10-25 10:12:53 +08:00
clsty 5a050be3de Fix path in exp-update-old.sh 2025-10-25 08:43:41 +08:00
clsty d8aa0de443 Bring back old update.sh (#2284) 2025-10-25 08:11:42 +08:00
clsty 7662e4f904 Update exp-update-old.sh 2025-10-25 07:29:52 +08:00
clsty b0d64d00b6 (WIP) Bring back old update.sh (#2284) 2025-10-25 07:23:19 +08:00
end-4 9dd8f32595 make notif action buttons larger 2025-10-25 00:13:52 +02:00
end-4 99dd0a4e2e make notif status row less weird 2025-10-25 00:11:17 +02:00
end-4 531411315e region selector: remove auto fullscreen ocr, make close btn fab
ocr-ing the whole screen slow and messy. it's better to just go with the regular flow of selecting a region
2025-10-24 23:45:08 +02:00
end-4 e6eb53796d fix calendar occasionally get placed at funny position 2025-10-24 18:42:10 +02:00
end-4 a3ced86214 don't create homework folder before it's necessary (#2264) 2025-10-24 17:37:34 +02:00
end-4 435ff32904 sidebar: use friendlier name for idle inhibitor toggle 2025-10-24 17:37:14 +02:00
clsty e1270836d0 Update sdist/nix/README.md 2025-10-24 22:10:19 +08:00
end-4 93f8d0990f right sidebar: fix unused quick toggles being movable 2025-10-24 15:11:27 +02:00
end-4 b23a2d4f2c region selector: fix dismiss button 2025-10-24 13:10:18 +02:00
end-4 d031087972 ocr: use all available langs 2025-10-24 11:39:21 +02:00
end-4 cdf24a1c19 region selector: fix circle dragging being forced into a target region 2025-10-24 11:24:47 +02:00
end-4 e857d538fb region selector: make circle selection not amogus large 2025-10-24 10:29:48 +02:00
end-4 3bd699c9e6 use quickshell region selector for ocr 2025-10-24 00:26:47 +02:00
end-4 6f756f48cb settings: add roman ws number preset 2025-10-23 23:41:56 +02:00
end-4 b14a5b3dd9 settings: add ws number map presets 2025-10-23 23:32:11 +02:00
end-4 5f23f6caa3 brightness: adjust antiflashbang delays, indicate nightlight on osd 2025-10-23 19:29:37 +02:00
end-4 d05ae5231c add fallback script for google lens keybind 2025-10-23 19:07:18 +02:00
end-4 07d3eea1d1 workspace_action.sh: format 2025-10-23 19:06:39 +02:00
end-4 23830f3454 work safety: disabled by default, add toggle to settings app 2025-10-23 16:47:06 +02:00
end-4 24ae5d327e notif groups: expand on right press instead of release 2025-10-23 16:46:51 +02:00
end-4 7b9454b101 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-23 09:45:16 +02:00
end-4 b976ba17d5 region selector: cleanup after image search 2025-10-23 09:45:05 +02:00
clsty 9c803164e1 Remove .gitattributes 2025-10-23 15:33:16 +08:00
end-4 b9592b30af Show passive items in the system tray (#2251) 2025-10-23 09:26:00 +02:00
end-4 a536e1600d make night light color temp slider more intuitive 2025-10-23 09:19:07 +02:00
end-4 6267e54ad7 brightness: animate change for laptop screens, prevent pitch black w/ anti flashbang 2025-10-23 09:00:52 +02:00
end-4 11b337b189 anti flashbang: pass image directly to magick thru stdio, more triggers 2025-10-23 08:59:59 +02:00
Yosuke Nishiyama 20d34eb622 change name to "filterPassive" 2025-10-22 23:28:04 +01:00
Yosuke Nishiyama 416df97b64 Merge branch 'end-4:main' into patch-1 2025-10-22 23:26:44 +01:00
end-4 b3cabb788b anti flashbang: clean up when done 2025-10-23 00:22:35 +02:00
end-4 c620c11ba8 region selector: lower aim lines opacity 2025-10-23 00:06:23 +02:00
end-4 7515f77846 region selector: add option to show/hide coord aim lines 2025-10-23 00:05:19 +02:00
end-4 b35ef90916 add anti flashbang
could be improve with smooth fading
2025-10-22 23:56:50 +02:00
end-4 a4d2a720d0 fix deprecated Connections syntax 2025-10-22 23:55:39 +02:00
clsty 8141e15bd9 Add subcmds; Not skip backup unless input y/n 2025-10-23 05:20:22 +08:00
Celestial.y 064488a9c4 Not overwrite other things under quickshell 2025-10-23 04:36:40 +08:00
end-4 bb08c61b76 sidebar: night light dialog 2025-10-22 22:16:58 +02:00
end-4 6ed9c9869e styledslider: make marks with any range 2025-10-22 22:16:45 +02:00
end-4 586d7d4f9b sidebar: unfuck non-default quick toggles configurations 2025-10-22 22:15:26 +02:00
end-4 0ac96e02ab brightness service: more edging 2025-10-22 22:13:23 +02:00
end-4 63be9874f4 systeminfo: add gentoo 2025-10-22 17:46:41 +02:00
end-4 c1393ce7c7 region selector: animate icon on mode change 2025-10-22 17:46:30 +02:00
end-4 973d0c0c07 make region selector more readable in light theme 2025-10-22 09:22:58 +02:00
clsty c4f81e7027 Update quickshell version (gentoo) 2025-10-22 08:25:26 +08:00
end-4 ed0289df3b adjust screenshot regions opacity 2025-10-22 01:46:52 +02:00
end-4 7e4cbaf5df revamp region selector 2025-10-22 01:43:13 +02:00
end-4 bce8b6f9a8 make sidebar classic toggle button icons have size consistent with toolbar 2025-10-22 01:28:11 +02:00
end-4 0718546167 refractor icon toolbar buttons 2025-10-22 01:27:29 +02:00
end-4 8e222eb40d update qs version 2025-10-21 23:05:01 +02:00
end-4 fddb7ecc05 remove redundant imports 2025-10-21 22:58:26 +02:00
end-4 b5ae6f01eb Refactor import to be compatible with new version of quickshell (#2263) 2025-10-21 22:56:44 +02:00
Filip Janus ecd7a225e9 fix bar module reference 2025-10-21 22:43:54 +02:00
Filip Janus f2e4508cfc refactor import to be compatible with new version of quickshell 2025-10-21 22:36:56 +02:00
end-4 4031925e11 fix "no active player" popup positioning for vertical bar 2025-10-21 20:49:42 +02:00
end-4 a99f6cac5e sidebar: fix weird anim on toggle buttons 2025-10-21 20:10:52 +02:00
end-4 d5bccd9bb1 hide code: entries from cheatsheet for zoom keybinds 2025-10-21 17:51:55 +02:00
end-4 94102cec97 fix kill dialog not writing "always" properly (#2232) 2025-10-21 17:43:15 +02:00
end-4 778620c312 translation?service?:safer?access??? 2025-10-21 16:40:53 +02:00
end-4 c50a505cdb fix screenshot button 2025-10-21 16:06:16 +02:00
end-4 1830aeba18 make left sidebar padding consistent with right sidebar 2025-10-21 13:27:15 +02:00
end-4 1ba6b761f0 allow corner hover open for horizontal bar 2025-10-21 13:22:55 +02:00
clsty b1921b7847 Update message 2025-10-21 15:42:35 +08:00
clsty f37fa1b071 Finish adding auto-close-issue.yml 2025-10-21 15:25:45 +08:00
clsty a79201ebd7 Improve auto-close-issue.yml 2025-10-21 15:24:06 +08:00
clsty b557586a62 Try to fix auto-close-issue.yml 2025-10-21 15:13:12 +08:00
clsty 1842ab790e Try to fix auto-close-issue.yml 2025-10-21 15:04:10 +08:00
clsty e8937e2030 Try to fix auto-close-issue.yml 2025-10-21 15:01:16 +08:00
clsty 2ddfc77b66 Try to fix auto-close-issue.yml 2025-10-21 14:58:15 +08:00
clsty 00526116cc Try to fix auto-close-issue.yml 2025-10-21 14:53:43 +08:00
clsty 1c2bfb7991 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-10-21 14:51:46 +08:00
clsty fa52acad27 Add auto-close-issue workflow (WIP) 2025-10-21 14:49:09 +08:00
Celestial.y 18c11899cb Update package-installers.sh 2025-10-21 13:40:03 +08:00
clsty 3cd323cb1a Add --skip-quickshell for install-files.sh 2025-10-21 09:42:29 +08:00
Celestial.y 09c894db0a Gentoo Typo (#2257) 2025-10-21 09:28:50 +08:00
jwihardi 3f030805d1 gui-misc -> app-misc 2025-10-20 21:15:35 -04:00
Celestial.y e96be21850 Gentoo Quickshell Fix (#2256) 2025-10-21 09:10:44 +08:00
jwihardi 9242b93558 quickshell, widgets, install, useflag (breakpad), keywords - updated 2025-10-20 20:35:43 -04:00
jwihardi 4de08c438b Delete sdist/gentoo/illogical-impulse-quickshell-git/quickshell-9999.ebuild 2025-10-20 19:16:27 -04:00
jwihardi 576311f7b2 Merge branch 'end-4:main' into quickshell-fix 2025-10-20 19:16:01 -04:00
jwihardi bf96099e46 fixed package name 2025-10-20 19:14:38 -04:00
jwihardi 854edba825 added live quickshell ebuild with specific commit 2025-10-20 18:42:59 -04:00
end-4 fe3e5de518 sidebar: quick toggles: larger icon size when 1 cell wide 2025-10-20 23:12:58 +02:00
end-4 d5b1e9f40c sidebar: quick toggles: smoother size change 2025-10-20 22:56:33 +02:00
end-4 54fe878580 right sidebar: containerize top row elements 2025-10-20 22:25:23 +02:00
end-4 075a21a9db make google lens tool use normal region selection by default 2025-10-20 22:00:08 +02:00
end-4 cc605e24d9 region selector: fix target regions 2025-10-20 21:09:27 +02:00
end-4 4ea7401190 circle to search 2025-10-20 21:03:03 +02:00
Yosuke Nishiyama 3b4525413a typo 2025-10-20 18:43:17 +01:00
Yosuke Nishiyama 8bf59faf66 add config option for smartTray 2025-10-20 18:38:45 +01:00
Yosuke Nishiyama 54b4dd7818 Merge branch 'end-4:main' into patch-1 2025-10-20 18:33:38 +01:00
end-4 21b3cca54a hyprland: update keybinds+rules for previous commit 2025-10-20 13:13:54 +02:00
end-4 af65c39c87 make screen snip built into the shell so it's faster (#2113) 2025-10-20 13:13:01 +02:00
end-4 1d51cc3388 keybinds: make office keybind match windows, allow record when locked 2025-10-20 09:43:25 +02:00
Yosuke Nishiyama b6c1cd504e Show passive items in the system tray 2025-10-19 23:31:05 +01:00
end-4 ba0f2248d8 make notif items also draggable to left 2025-10-20 00:20:06 +02:00
end-4 96605fb0fe make notifs dismissable in both directions 2025-10-20 00:15:27 +02:00
end-4 991abd4c1c update default quick toggles 2025-10-20 00:03:15 +02:00
end-4 fec23cab8d right sidebar: move audio controls to dialogs 2025-10-19 23:58:45 +02:00
end-4 0fe7bdc5b5 feat: sound alerts for battery and pomodoro (#2223) 2025-10-19 21:37:25 +02:00
end-4 65557dfb3d fix sound plays every time low and charge state changes
instead of just when it goes to low
2025-10-19 21:37:10 +02:00
end-4 ad907a72a1 Merge branch 'fix-scaling' of https://github.com/sola-contrib/dots-hyprland 2025-10-19 21:20:57 +02:00
end-4 c65aea86c6 qs: use more neutral default pallete 2025-10-19 21:17:23 +02:00
end-4 76dd63a326 feat: Add screen recording button and config toggle (#2219) 2025-10-19 20:53:48 +02:00
end-4 8798b4e826 settings: make bar screen record util button toggle name shorter 2025-10-19 20:53:23 +02:00
end-4 7b1fa1246f bar: record util button off by default 2025-10-19 20:51:46 +02:00
end-4 f3e4773811 utilbuttons: record button: allow region selection 2025-10-19 20:51:05 +02:00
end-4 233b4c78ab settings: add api key note for ai translation 2025-10-19 13:11:02 +02:00
end-4 f81d316ad4 roundcorner: use switch fallthrough for fewer dupe returns 2025-10-19 10:29:24 +02:00
end-4 f123e90392 resourcePopup: fix unqualified access 2025-10-19 10:27:20 +02:00
clsty d0607c789f Add -f for makepkg 2025-10-19 16:15:32 +08:00
clsty 85278ea147 Ask once instead of 3 times for backup 2025-10-19 15:44:44 +08:00
clsty 9cbe0f38f9 Update comment in PKGBUILD 2025-10-19 14:32:38 +08:00
clsty 6bcb20ee4c Pin commit for quickshell-git (#2238) 2025-10-19 14:28:53 +08:00
clsty ca104160b0 Update showhelp 2025-10-19 11:53:34 +08:00
clsty bc13baa5a9 Update showhelp_global() 2025-10-19 11:32:22 +08:00
clsty 2014a030d6 Deprecate install.sh in favor of setup
Still decide to deprecate install.sh cuz TAB completion can not be done
without intrusive and automatic method, so just use ./setup instead.
2025-10-19 11:22:24 +08:00
clsty f673cae32b Update diagnose 2025-10-19 10:29:06 +08:00
clsty f5d09d569c Update comment 2025-10-19 09:52:11 +08:00
clsty 94749c1c69 Update comment 2025-10-19 09:35:46 +08:00
clsty 9c216036ec Update message 2025-10-19 09:33:53 +08:00
clsty 7e8750f79b Fix subcmd exp-uninstall --help 2025-10-19 09:06:18 +08:00
clsty 8ca46aecdd Using ./setup install instead of ./install.sh 2025-10-19 08:44:12 +08:00
clsty 0e6779fafc Fixes for install scripts 2025-10-19 06:59:33 +08:00
Celestial.y acde0218b3 Update the update script (#2220) 2025-10-19 06:54:23 +08:00
clsty b8a1955ab9 Update showfun() 2025-10-19 06:53:23 +08:00
Bishoy Ehab e49426c027 Fix a UI issue 2025-10-19 00:55:15 +03:00
Bishoy Ehab 00d547362b Remove the smoke-test 2025-10-19 00:49:04 +03:00
Bishoy Ehab cce6e821c2 Maybe fix the smoke-test 2025-10-19 00:48:03 +03:00
Bishoy Ehab a48ebfc4c1 Fixed the test and update script 2025-10-19 00:40:00 +03:00
Bishoy Ehab b23bdb0188 Test 2025-10-19 00:07:54 +03:00
Bishoy Ehab 69b92b57aa Update the update, update tester, functions scripts 2025-10-18 23:33:25 +03:00
end-4 84d692feef Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-18 22:12:49 +02:00
end-4 6834d41f4b sidebar: quick toggles: fix weird anim on startup 2025-10-18 22:12:40 +02:00
end-4 9fad405064 readme: update "some widgets" screenshot 2025-10-18 22:06:58 +02:00
end-4 a8ddbb5d2d sidebar: quick toggles: add missing tooltips 2025-10-18 21:54:13 +02:00
Bishoy Ehab 1fd328f90a Test the changes that have been made 2025-10-18 22:53:52 +03:00
end-4 6779fa90a5 sidebar: make status text of some toggles make more sense 2025-10-18 21:42:23 +02:00
end-4 45d6bfa3fb sidebar: quick toggles: fix iilegal default 2025-10-18 21:42:03 +02:00
end-4 5d1a9b1e9c sidebar: android-style quick toggles & sliders (#2217)
Co-Authored-By: Vague Syntax <173799252+vaguesyntax@users.noreply.github.com>
2025-10-18 19:07:10 +02:00
end-4 77ae119d32 fix gemini clock theming (forgor mkdir) 2025-10-18 09:58:59 +02:00
Bishoy Ehab 0facd08fa9 Merge branch 'end-4:main' into main 2025-10-17 21:33:50 +03:00
clsty 0ccdc47034 Improve/Fix showhelp 2025-10-18 01:24:26 +08:00
clsty 7c21ec0c5a Rename scripts, move into sdata/step 2025-10-18 00:54:58 +08:00
clsty 731beb0f7c Better integration; introduce subcommand 2025-10-18 00:38:49 +08:00
end-4 9a170a3c5b fix settings app cant change time format 2025-10-17 18:04:37 +02:00
end-4 f93d629acb sidebar: add scroll to bottom button 2025-10-17 18:00:11 +02:00
Bishoy Ehab eede0e3c34 Merge branch 'end-4:main' into main 2025-10-17 16:27:20 +03:00
Bishoy Ehab f4f97be46d Remove a useless condition 2025-10-17 16:16:39 +03:00
Bishoy Ehab 3bea2a314e Fix: Suppress /dev/tty error in safe_read 2025-10-17 14:50:26 +03:00
Bishoy Ehab 4d20de926c Fix: Prevent script exit in while-read loop 2025-10-17 14:48:16 +03:00
Bishoy Ehab b307b4ed95 Return the old update script 2025-10-17 14:35:32 +03:00
Bishoy Ehab 653cba4d4e Test 2025-10-17 14:33:37 +03:00
Bishoy Ehab adb93e382f Test 2025-10-17 14:32:56 +03:00
Bishoy Ehab b2938ef678 Test 2025-10-17 14:32:46 +03:00
Bishoy Ehab 809c8806d0 Test 2025-10-17 14:31:54 +03:00
Bishoy Ehab d809c2e789 Test 2025-10-17 14:30:03 +03:00
Bishoy Ehab ca2d073775 Maybe something fixed? 2025-10-17 14:13:16 +03:00
Bishoy Ehab 4038c437c6 Merge branch 'main' of https://github.com/BeshoyEhab/dots-hyprland 2025-10-17 13:54:42 +03:00
Bishoy Ehab 12011fd0c8 Enhance the logic for pass the args to update script 2025-10-17 13:54:02 +03:00
Bishoy Ehab 528ae04711 Update install script to pass the update args 2025-10-17 13:44:23 +03:00
Celestial.y 7612a3f742 Use local var for args_includes 2025-10-17 18:35:12 +08:00
Bishoy Ehab 2272b94531 Update the update and options and install to correctly pass the args to update script 2025-10-17 13:21:32 +03:00
Celestial.y 21d628b598 Try to fix backup 2025-10-17 17:49:20 +08:00
Bishoy Ehab ab0049ec5c Integrate update script into install.sh 2025-10-17 12:16:55 +03:00
Bishoy Ehab ac394784e3 Merge branch 'end-4:main' into main 2025-10-17 12:10:20 +03:00
end-4 943a72ce12 Fix escape keybind notification for virtual machines (#2222) 2025-10-17 07:05:23 +02:00
Celestial.y 927d9b0f85 Fix diagnose 2025-10-17 11:33:03 +08:00
Celestial.y 7454087c88 Fix backup function typo 2025-10-17 11:15:56 +08:00
0blivi0nis 37fd19fc9a feat: sound alerts for battery and pomodoro 2025-10-16 19:03:14 -07:00
Alvin aa90e75c59 Fix escape keybind notification for virtual machines 2025-10-16 21:13:35 -04:00
Bishoy Ehab 7b090c2e2a Fix some issues in the test_update script 2025-10-17 01:14:45 +03:00
Bishoy Ehab 1a4a8d87fc Update the test script 2025-10-17 00:20:28 +03:00
Bishoy Ehab fbd0644942 Fix some security issues and remove non-used function 2025-10-17 00:16:09 +03:00
Bishoy Ehab 4eb4f635e7 Add test_update sctipt 2025-10-16 23:52:34 +03:00
Bishoy Ehab 60d6bfae9f Update the Warning message 2025-10-16 23:43:33 +03:00
Bishoy Ehab 009345c5f6 Fix the local used outside a function issue 2025-10-16 23:38:18 +03:00
Bishoy Ehab 00d4d368df Enhance the update script 2025-10-16 23:35:27 +03:00
Cleboost 5fda1cdc61 fix: Invoke record script via bash -c with ~ expansion 2025-10-16 22:07:29 +02:00
Cleboost 91955ef66c Add screen recording button and config toggle 2025-10-16 22:02:00 +02:00
Celestial.y 89585f8121 Updata uv/README.md 2025-10-16 22:22:08 +08:00
end-4 449df7f161 background: fix(??) bg clock paralax (??) 2025-10-16 11:52:14 +02:00
end-4 a5170c51b3 sidebar: add option for hover open at end of hover region 2025-10-16 09:59:36 +02:00
end-4 20bda361a3 Fix bad keyboard layout if variant name has commas (#2186) 2025-10-16 09:38:37 +02:00
end-4 ca7ae4e1e8 Fix Booru pending query not dismissing when fetch fails (#2207) 2025-10-16 09:31:53 +02:00
end-4 6f08589265 adjust bg clock parallax factor 2025-10-16 09:21:25 +02:00
end-4 ac5c902569 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-16 09:20:46 +02:00
end-4 731b5cccad fix bg clock parallax 2025-10-16 09:20:11 +02:00
end-4 fd1e82bd8e Delete items in clipboard history with Shift+Del (#2199) 2025-10-16 09:12:51 +02:00
end-4 2140eff9af add qs and qt version check to diagnosis script 2025-10-16 09:01:58 +02:00
André Zanghelini 6f97bb2635 Allow OSK keyboard for German and Russian variants 2025-10-16 03:58:52 -03:00
André Zanghelini fd0b5f4377 Fix bad keyboard layout if variant name has commas 2025-10-16 03:58:52 -03:00
André Zanghelini c5bd1d6bc0 Shift+Del to delete item in clipboard history 2025-10-16 03:58:16 -03:00
André Zanghelini 40ba90df27 Drop running booru fetch and alert on fetch error 2025-10-16 03:57:43 -03:00
clsty 450a1493fe Update STY_ vars 2025-10-16 12:14:54 +08:00
Celestial.y 3b1f9aa41e Fix syntax error in if statement (#2214) 2025-10-16 11:43:50 +08:00
TheBITLINK aka BIT e993671d02 Fix syntax error in if statement 2025-10-16 00:32:57 -03:00
clsty b36758a155 Rename revision number for ebuilds (#2211) 2025-10-16 11:06:01 +08:00
clsty 14a46622c3 Fix naming 2025-10-16 10:31:13 +08:00
clsty 9aea0f1034 Update prompt 2025-10-16 10:20:06 +08:00
clsty 8e87a7aa99 Improve backup_configs, only backup clashing ones (#1863) 2025-10-16 10:12:38 +08:00
Celestial.y 4d31886e4a Update sdist/arch/README.md 2025-10-16 08:41:41 +08:00
Celestial.y 4886f87afa Fix path in .gitignore 2025-10-16 08:00:30 +08:00
Celestial.y 923b22a75a Fix path in CONTRIBUTING.md 2025-10-16 07:59:56 +08:00
clsty 610ac47289 Fix path in update.sh 2025-10-16 07:47:32 +08:00
clsty de28b8d314 Fix permission 2025-10-16 07:46:06 +08:00
clsty 7c50f6c8d0 Fix 3.install-files.sh 2025-10-16 07:41:22 +08:00
clsty 8b493e091d Rearrange for tidier structure (#2212) 2025-10-16 07:19:55 +08:00
end-4 13065d7e5a settings: add toggle for wallpaper selector use system file picker 2025-10-15 19:27:14 +02:00
clsty 3f7d6759c1 Update gentoo/outdate-detect-mode to AUTO 2025-10-15 19:15:37 +08:00
end-4 a4be03cd5f enable icon fill anim again 2025-10-15 13:06:41 +02:00
end-4 44d5994248 screenshot: dont put region size in the region 2025-10-15 10:11:24 +02:00
Celestial.y d8b6d52a85 dist-gentoo updates (#2155) 2025-10-15 15:39:16 +08:00
jwihardi e0e6054f2f Clean up blank lines in install-deps.sh
Removed unnecessary blank lines in install-deps.sh.
2025-10-15 00:03:28 -04:00
jwihardi eeed0c0b1a Merge branch 'end-4:main' into main 2025-10-15 00:01:17 -04:00
jwihardi 5fbdea2cae Merge pull request #2 from jwihardi/symbols
Symbols
2025-10-15 00:00:44 -04:00
jwihardi 393944a8a7 Update README with Hyprland known issues
Added troubleshooting steps for Hyprland emerging issues.
2025-10-14 23:58:53 -04:00
jwihardi a442e2be91 added another initial print 2025-10-14 23:48:32 -04:00
jwihardi 18398e1b93 fonts-themes was an r1 build? Why? 2025-10-14 23:43:02 -04:00
jwihardi 1b08584ced fonts now installs symbols and space grotesk 2025-10-14 23:42:23 -04:00
end-4 20a3da8a19 left sidebar: more animated placeholders 2025-10-14 23:52:46 +02:00
end-4 1dd4c4a109 ai-generated ui translations 2025-10-14 18:50:01 +02:00
end-4 a228c54dd5 remove debug print 2025-10-14 18:48:26 +02:00
end-4 125d3c0a4d translations: update en_US keys 2025-10-14 17:56:50 +02:00
end-4 c9f5397821 translation tools: add -y/--yes flag 2025-10-14 12:22:16 +02:00
end-4 57a5c0f743 move translations into quickshell folder 2025-10-14 12:02:33 +02:00
end-4 8dc31cc790 background: make clock have slightly different parallax movement 2025-10-14 11:58:37 +02:00
end-4 fd1d74ada1 refractor gemini-categorize-wallpaper.sh 2025-10-14 10:19:09 +02:00
end-4 28756860aa cookie clock: fix bubble date's bubbles being the same 2025-10-14 09:29:41 +02:00
end-4 5929533d78 cookie clock: fix jagged rotating date 2025-10-14 09:28:42 +02:00
end-4 395baf1509 Don't scroll when deleting clipboard history items (#2198) 2025-10-14 09:22:14 +02:00
end-4 b4d89b66f5 Fix command key formatting in SearchWidget.qml 2025-10-14 09:21:18 +02:00
André Zanghelini e9f803b8a5 Don't scroll when deleting clipboard history items 2025-10-14 01:34:38 -03:00
clsty 8b25dca1dc Update install scripts 2025-10-14 12:23:10 +08:00
clsty 514363247a Update 1.install-deps-selector.sh 2025-10-14 12:13:28 +08:00
jwihardi 354a415e73 Merge pull request #1 from jwihardi/clean-testing
Clean testing
2025-10-13 23:03:27 -04:00
jwihardi 4df5de3122 Merge branch 'main' into clean-testing 2025-10-13 23:02:47 -04:00
jwihardi e5815974b1 Update ebuild to remove local material symbols font
Removed installation of material symbols font to local user directory.
2025-10-13 23:01:55 -04:00
jwihardi 2ff8e8fa67 Merge branch 'end-4:main' into main 2025-10-13 23:01:27 -04:00
clsty dd7038adf2 Use README.md instead of comment.(#1061) 2025-10-14 10:54:25 +08:00
clsty 39d25107bd Update comment (#1061) 2025-10-14 10:49:14 +08:00
jwihardi 2c671578ae added material-design symbols 2025-10-13 22:37:45 -04:00
jwihardi 76680ba86c chowns not needed usually 2025-10-13 21:34:47 -04:00
jwihardi 4d83c5a8f9 fixed i2c group detection 2025-10-13 21:12:43 -04:00
jwihardi 274a857dff added python:3.12 2025-10-13 20:58:28 -04:00
clsty c891c9a921 Update dist-*/README.md; Update comment 2025-10-14 08:34:54 +08:00
jwihardi 247a8e0cca Merge branch 'end-4:main' into clean-testing 2025-10-13 18:51:39 -04:00
jwihardi 15c0ab6279 Merge branch 'end-4:main' into main 2025-10-13 18:50:47 -04:00
jwihardi 5c7c21fdf1 fixed typo 2025-10-13 18:49:44 -04:00
jwihardi 14348306e2 updated guru to match main 2025-10-13 18:49:05 -04:00
jwihardi 02cc4c1aa2 moved additional useflags to another file 2025-10-13 18:45:51 -04:00
jwihardi 1aadbfc019 Update README.md with known issues for Hyprland
Added known issues section for Hyprland installation.
2025-10-13 18:05:35 -04:00
end-4 b53e657091 move Translation to services folder 2025-10-13 23:42:34 +02:00
end-4 74967cbac8 crosshair: fix wrong ipc handler target name 2025-10-13 23:42:22 +02:00
end-4 a139451a9b readme: update first screenshot 2025-10-13 21:39:04 +02:00
end-4 7708372922 make vm submap keybind more friendly for eroges
prevents ctrl skip
2025-10-13 21:13:58 +02:00
jwihardi 09146ec176 added more use flags 2025-10-13 15:13:00 -04:00
jwihardi 3abadb666e added gtkmm use flag 2025-10-13 15:11:15 -04:00
end-4 be164a823d fix notif unread indicator showing even when sidebar is open 2025-10-13 20:57:13 +02:00
end-4 d5dda1722a update wallpapers service to use venv wrapped thumbgen (#2143) 2025-10-13 20:19:12 +02:00
end-4 28ea9a7861 wrap thumbgen in venv script, add missing deactivates (#2143) 2025-10-13 20:16:39 +02:00
jwihardi ec87635e8e Fix useflag for dev-libs/qcoro 2025-10-13 13:58:33 -04:00
jwihardi 48219fbd95 Add freetype and harfbuzz use flags 2025-10-13 13:52:42 -04:00
jwihardi 33b5202a5d Add VLC and qcoro use flags 2025-10-13 13:47:46 -04:00
jwihardi 141fa55869 Merge branch 'end-4:main' into clean-testing 2025-10-13 13:36:57 -04:00
jwihardi 2a2e2da879 Merge branch 'end-4:main' into main 2025-10-13 13:36:45 -04:00
end-4 73bd73d910 cookie clock: adjust space preset 2025-10-13 19:33:09 +02:00
end-4 9d733fcff5 Fix dominant color from least_busy_region as BGR (#2187) 2025-10-13 17:56:31 +02:00
end-4 307c543d8d Add more status in the network icon (#2154) 2025-10-13 17:52:43 +02:00
end-4 5ffd1c85d3 Fix: Preserve chronological order of clipboard history (#2190) 2025-10-13 17:46:16 +02:00
end-4 f771d47526 update he_HE translation (#2189) 2025-10-13 17:43:44 +02:00
end-4 50e73d4a3a set config read/write delay to 0 where delay is unnecessary 2025-10-13 17:35:08 +02:00
end-4 6cc96d094d update work safety file keyword list 2025-10-13 17:29:33 +02:00
TheAnnoying dc149d2636 Update he_HE.json 2025-10-13 17:40:05 +03:00
TheAnnoying 6a9fd04989 Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:37:29 +03:00
TheAnnoying 7c01257cdd Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:37:19 +03:00
TheAnnoying fa99a0b3c8 Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:37:13 +03:00
TheAnnoying cec8dc991c Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:37:07 +03:00
TheAnnoying 2b78225114 Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:37:01 +03:00
TheAnnoying 2ffec8014a Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:36:56 +03:00
TheAnnoying 30f2db1e4d Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:36:50 +03:00
TheAnnoying 1b44b27142 Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:36:44 +03:00
TheAnnoying badc1249c0 Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:36:38 +03:00
TheAnnoying 8621b3f6ff Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:36:30 +03:00
TheAnnoying e67d8e9c81 Update .config/quickshell/translations/he_HE.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-13 17:36:22 +03:00
ew 769ad73737 Handle empty search in fuzzyQuery function
Add check for empty search string in fuzzyQuery function.
2025-10-13 22:33:08 +08:00
TheAnnoying afb14409c2 chore: string syncing and translation 2025-10-13 17:08:17 +03:00
end-4 971aaf3b98 cookie clock: fix shadow not including date bubbles 2025-10-13 15:19:14 +02:00
end-4 2d2145a780 bg clock: fix cursed bubble date 2025-10-13 15:11:58 +02:00
end-4 28078910a2 adjust abstract wallpaper clock style 2025-10-13 15:11:34 +02:00
end-4 6235e6e665 settings: fix untranslatable text 2025-10-13 15:00:50 +02:00
end-4 5bf63bc36c adjust stupid config rw delay 2025-10-13 15:00:31 +02:00
end-4 02192368d2 add option to use hyprlock instead of quickshell 2025-10-13 12:16:42 +02:00
end-4 b0cfcaff3d anime: fix anchors in layout 2025-10-13 12:13:37 +02:00
end-4 d208b07a94 config: lower read/write timer interval 2025-10-13 11:56:48 +02:00
end-4 e715478310 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-13 11:24:04 +02:00
end-4 5dedbf91e0 add gemini powered clock styling 2025-10-13 11:24:02 +02:00
clsty 64e04ae15b Update CONTRIBUTING.md 2025-10-13 13:40:33 +08:00
clsty 573105d269 Add TODO in diagnose 2025-10-13 13:32:52 +08:00
André Zanghelini 8fc6a4b349 Fix dominant color from least_busy_region as BGR 2025-10-13 02:10:40 -03:00
jwihardi c6c76be8f9 Fix formatting in README.md for clarity 2025-10-13 00:54:19 -04:00
jwihardi 1cd15ffa53 Fix formatting and wording in known issues section 2025-10-13 00:53:07 -04:00
jwihardi eb9c3f7867 Fix typo in README regarding Hyprland ebuild 2025-10-13 00:46:00 -04:00
jwihardi a369409930 Update README with known issues for Hyprland
Add known issues section for Hyprland installation.
2025-10-13 00:45:36 -04:00
jwihardi ad6788f67a Add sonnet USE flag for kde-frameworks
Add sonnet USE flag for kde-frameworks.
2025-10-13 00:35:53 -04:00
jwihardi 28de204036 Fix typo in kde-frameworks/kconfig entry 2025-10-12 23:46:35 -04:00
jwihardi cf5bfb16bd Add new use flags for kde-frameworks and app-crypt 2025-10-12 23:44:50 -04:00
jwihardi 5642d379a5 Add xmlto with text use flag
Added 'app-text/xmlto' with 'text' use flag.
2025-10-12 23:36:23 -04:00
jwihardi e33992ecf8 Update keywords 2025-10-12 23:34:14 -04:00
jwihardi fa85e0cc68 Add brightnessctl and update libxkbcommon keyword 2025-10-12 23:27:37 -04:00
jwihardi 42ee8d9ca4 Update README with use flags and service recommendations
Clarify recommended use flags and dot-files setup instructions.
2025-10-12 23:26:51 -04:00
clsty d521e014fd Update README.md 2025-10-13 11:16:42 +08:00
jwihardi 43545bce41 Merge branch 'end-4:main' into main 2025-10-12 23:11:33 -04:00
end-4 78723402ee refractor bar unread notif indicator, add count option in settings 2025-10-12 23:35:59 +02:00
jwihardi 9698974ad7 Merge branch 'end-4:main' into main 2025-10-12 17:16:03 -04:00
end-4 6f138677a8 settings: allow larger bg clock cookie side # range 2025-10-12 22:17:19 +02:00
end-4 9161044860 adjust critical notif cookie 2025-10-12 22:17:01 +02:00
end-4 30e804acd8 settings: fix inconsistent content section text color 2025-10-12 20:35:57 +02:00
end-4 40fe0bebcf prevent empty sidebar 2025-10-12 20:17:31 +02:00
end-4 4f25572d1d make critical notif icon more readable 2025-10-12 20:17:12 +02:00
end-4 81cc35702d sidebar: add option to disable translator tab 2025-10-12 19:53:42 +02:00
end-4 cd3ed42b6d make symbols on left sidebar wrapped with a pentagon 2025-10-12 18:43:59 +02:00
end-4 4637b82471 make urgen notifs have cookie shape 2025-10-12 18:34:20 +02:00
clsty e1d77c0c3e Add --sudoloop for yay (#823) 2025-10-12 23:08:51 +08:00
end-4 bc688792cb make tray context menu animate faster 2025-10-12 16:31:52 +02:00
end-4 36b33ba4f1 make some buttons trigger on mouse down to feel faster 2025-10-12 16:30:41 +02:00
end-4 edde61a46c bg clock: make second hand anim more continuous 2025-10-12 16:27:32 +02:00
end-4 aa1fcd7eb9 ai chat: fix message not fade in until the end when there's code blocks 2025-10-12 14:17:54 +02:00
end-4 3f59e2078a ai: fade in: prevent random monospaced text 2025-10-12 13:13:43 +02:00
end-4 c2edd26598 ai chat: adjust msg header style 2025-10-12 13:13:25 +02:00
end-4 a0ceed9586 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-12 12:58:05 +02:00
end-4 a6e360c1db ai: fade in response 2025-10-12 12:58:03 +02:00
end-4 79b49bd57e fix material theme loader connections warning 2025-10-12 12:56:13 +02:00
end-4 0c1b7abe36 add Qt.callLater() to sidebar scroll to bottom (#2183) 2025-10-12 10:51:17 +02:00
end-4 6d39b63a74 bg clock: dont enable hour marks by default 2025-10-12 10:26:30 +02:00
end-4 438b2aac65 Unread notification count on bar (#2153) 2025-10-12 10:24:17 +02:00
end-4 3ffc25d5d8 add option to show/hide unread notif count 2025-10-12 10:23:34 +02:00
end-4 3b689f8a66 notif indicator: fix readability 2025-10-12 10:06:23 +02:00
end-4 2b62a5a0cc make notif indicator only show unread 2025-10-12 10:03:12 +02:00
end-4 7e46145df1 fix opening right sidebar with mouse not dismissing notifs 2025-10-12 09:59:29 +02:00
end-4 9655549739 Use thumbnail or wallpaper for Appearance (#2129) 2025-10-12 09:48:05 +02:00
end-4 57a3d1369b Appearance.qml: refractor wallpaperIsVideo check 2025-10-12 09:47:18 +02:00
end-4 2ae7a519d0 Hide Bluetooth widgets for systems without Bluetooth (#2167) 2025-10-12 09:43:10 +02:00
Woozepao 9165c6b706 Fix Jetbrain IDEs lose focus/rerendering problem (#2179) 2025-10-12 09:34:31 +02:00
jwihardi 7818864fac Merge branch 'end-4:main' into main 2025-10-12 00:59:16 -04:00
clsty 3f577f1088 Rename ex-files to exp-files 2025-10-12 10:22:05 +08:00
clsty 546435db6d Add --ex-files (#2137) 2025-10-12 10:20:44 +08:00
jwihardi c6f64a3acb added additional use flags 2025-10-11 21:13:45 -04:00
jwihardi c6b7652c6e added another warning and changed warning prints 2025-10-11 20:38:13 -04:00
jwihardi bfebd69568 Merge branch 'end-4:main' into clean-testing 2025-10-11 20:18:53 -04:00
jwihardi 3fb46f9604 Merge branch 'end-4:main' into main 2025-10-11 20:14:29 -04:00
end-4 17384f5761 Improve cookie clock style (#2117) 2025-10-11 18:18:00 +02:00
end-4 5a5328b1cb settings: cookie clock: fix wrong name/icon 2025-10-11 18:16:02 +02:00
end-4 edc83764c4 cookie clock: remove useless vars, adjust settings icons 2025-10-11 18:14:57 +02:00
end-4 1f5527164c settings: rearrange cookie clock settings 2025-10-11 17:58:24 +02:00
end-4 af5a7964d0 cookie clock: adjust colors and terminology 2025-10-11 17:52:08 +02:00
end-4 41c2814610 cookie clock: cleaner date indicator, adjust colors 2025-10-11 17:40:24 +02:00
end-4 c197f6eab2 bg clock: fix am pm parsing for 1 digit hours 2025-10-11 16:57:26 +02:00
end-4 410da66834 cookie clock: put hands in loaders 2025-10-11 16:55:20 +02:00
end-4 eb6a0e38f7 Include keypad numbers for keybinds with numbers (#2170) 2025-10-11 16:49:50 +02:00
Celestial.y 8e90c2898a Update post-installation link in install script 2025-10-11 22:23:02 +08:00
André Zanghelini 4074741187 Allow zoom with keypad 2025-10-11 10:49:41 -03:00
André Zanghelini 01bcab4af1 Allow keypad numbers for keybinds with numbers 2025-10-11 10:42:18 -03:00
end-4 6c5cc98016 make volume protection message translatable (#2164) 2025-10-11 15:24:36 +02:00
Ricardo Subtil b39618cd89 Disable Bluetooth buttons for systems without Bluetooth 2025-10-11 14:16:14 +01:00
end-4 22316b4684 fix anchor in layout 2025-10-11 11:50:34 +02:00
end-4 1e7e3a84c6 put time column in loader, use fewer Behaviors 2025-10-11 11:47:36 +02:00
end-4 872e0762b6 time column: fix am pm spacing 2025-10-11 11:22:55 +02:00
end-4 61fec4b53d background clock: hour marks: put in loader, reduce behavior spam 2025-10-11 11:20:15 +02:00
end-4 8e7b012c4c fix am pm matching 2025-10-11 11:18:32 +02:00
end-4 7ae53ac364 rename dateIndicator folder 2025-10-11 10:55:35 +02:00
end-4 c519505296 refractor MinuteMarks 2025-10-11 10:46:36 +02:00
end-4 a9b60c1d1b adjust quote style 2025-10-11 09:42:22 +02:00
end-4 22108934ff remove redundant DateIndicator 2025-10-11 09:27:28 +02:00
end-4 c93f8eafea Merge branch 'main' of https://github.com/darksignal7/dots-hyprland 2025-10-11 09:21:53 +02:00
end-4 856cfd3ebb hourhand: parameterize hand length 2025-10-11 09:20:42 +02:00
end-4 bccb516223 screen corner interaction: fix not working for vertical bar 2025-10-11 00:37:50 +02:00
end-4 53717588f9 screen corner interaction: make not unnecessarily enabled 2025-10-11 00:27:51 +02:00
end-4 4258d94d00 media controls: fix cover wrong after switching track, make not rely on cascade 2025-10-11 00:22:16 +02:00
end-4 01f8631663 disallow volume over 200% 2025-10-11 00:03:18 +02:00
end-4 393d90d3f7 fix colors not applied properly on first run 2025-10-10 23:58:45 +02:00
end-4 bd90e2c19e bar: fix tray overflow menu showing when empty 2025-10-10 23:47:27 +02:00
end-4 fe19cea6c9 search: add prefix for app search 2025-10-10 23:33:21 +02:00
jwihardi 56ab7f212e verbose is cringe, ask not needed 2025-10-10 17:15:24 -04:00
jwihardi 5179611c64 Merge branch 'end-4:main' into clean-testing 2025-10-10 17:14:18 -04:00
jwihardi 0c930294f1 Merge branch 'end-4:main' into main 2025-10-10 17:14:11 -04:00
end-4 8541dd3178 hyprland: use raw keycodes for ws binds so they work for funny kb layouts (#2157) 2025-10-10 23:08:39 +02:00
end-4 7e9a07838e hyprland: add note for raw keycode workspace binds 2025-10-10 23:06:44 +02:00
Celestial.y 7f2d1702ca Update comment in dist-update-notification.yml 2025-10-10 23:38:51 +08:00
Celestial.y b4b461d815 Update CONTRIBUTING.md 2025-10-10 22:46:28 +08:00
jwihardi bc75157b9f guru is correctly detected 2025-10-10 10:44:12 -04:00
jwihardi 67465045bb Merge branch 'end-4:main' into main 2025-10-10 10:31:07 -04:00
jwihardi 5dbfe00207 Merge branch 'end-4:main' into clean-testing 2025-10-10 10:30:38 -04:00
Celestial.y 38ac1723f6 Update 1-issue.yml 2025-10-10 22:16:16 +08:00
jwihardi af3ef1efde remove opencv useflags (invalid) 2025-10-10 10:06:32 -04:00
Hugo Vigne 3fba370e87 Update keybinds with code:... bindings for workspace navigation
Fixes https://github.com/end-4/dots-hyprland/issues/1705

Some keyboard layouts such as Azerty and Bépo defaults to symbols for the digits row, contrary to Qwerty-based layouts. Pressing Shift allows typing the actual digits instead of symbols.

Unfortunately, this breaks Workspace navigation in Hyprland configurations unless using keycodes for binding the digits row (1, 2, 3...0).

This commit does exactly that. It was tested with three keyboards, each time with 2 layouts: Azerty (French) / Qwerty (US).
The physical keyboards were:
- Asus Strix Scope II 96 Wireless
- Keychron Q3 HE QMK (ISO layout)
- The keyboard integrated in the Lenovo Thinkpad P16s Gen3 laptop.
2025-10-10 12:02:05 +02:00
jwihardi a28b1b5aa2 removed invalid atom 2025-10-10 02:34:07 -04:00
jwihardi aec5ef442e libxkmcommon needs to be unmasked for hyprland ebuild 2025-10-10 01:22:45 -04:00
jwihardi c907512cf0 Merge branch 'end-4:main' into main 2025-10-10 01:03:32 -04:00
jwihardi b87190993f added imagemagick 2025-10-10 01:03:22 -04:00
André Zanghelini 2d7cacbefb Add more status in the network icon 2025-10-10 00:17:06 -03:00
André Zanghelini 63e81369c2 Show notification indicator on "tray" 2025-10-09 23:08:25 -03:00
end-4 6f9bc17d57 deps: add imagemagick 2025-10-09 22:12:09 +02:00
Gwendolyn Page 7bd1810852 add Qt.callLater() around function calls to prevent leak 2025-10-09 13:54:49 -05:00
clsty 433fe1449a Update message 2025-10-10 01:12:05 +08:00
clsty b6566ec67b Update gentoo ebuild version 2025-10-10 00:58:08 +08:00
clsty b67b0baa1b Fix workflow 2025-10-10 00:55:18 +08:00
clsty 73e6d627bc Fix workflow 2025-10-10 00:43:21 +08:00
clsty e4ace3c416 Fix workflow 2025-10-10 00:40:54 +08:00
clsty b58c86cdd6 Fix workflow 2025-10-10 00:35:22 +08:00
clsty 9ff93169df Add dump github context workflow 2025-10-10 00:28:23 +08:00
clsty 44cdb3a52e Fix workflow 2025-10-10 00:23:07 +08:00
clsty 3d7fbba014 Fix workflow 2025-10-10 00:17:10 +08:00
end-4 ce1a397a7c wifi menu: fix double clicking always showing password prompt 2025-10-09 18:10:02 +02:00
clsty fa7da189fc Test commit on dist-arch 2025-10-09 23:32:03 +08:00
clsty 582fffda1b Fix workflow 2025-10-09 23:12:49 +08:00
darksignal7 3bf6f7ca09 fix: hide cookie quote on digital (am i blind or smthn?) 2025-10-09 17:45:04 +03:00
clsty 0a7c549125 Test commit on dist-arch 2025-10-09 22:42:33 +08:00
clsty 3bb510e910 Fix workflow 2025-10-09 22:39:40 +08:00
clsty 75a84f6ed1 Use DISCUSSION_NODE_ID 2025-10-09 22:28:41 +08:00
clsty a7aadd7439 Fix JSON parsing problem 2025-10-09 22:22:59 +08:00
clsty 1e90434c18 Fix curl no url 2025-10-09 22:21:17 +08:00
clsty d718f023cd Get notification node id first 2025-10-09 22:18:11 +08:00
darksignal7 28b47b25ea fix: hide cookie quote on lock screen 2025-10-09 17:06:41 +03:00
clsty 2bf933a3e1 Test commit on dist-arch 2025-10-09 21:53:22 +08:00
Celestial.y 24a548cd97 Update discussion ID in dist-update-notification.yml 2025-10-09 21:51:46 +08:00
Celestial.y ce307391a8 Test commit on dist-arch 2025-10-09 21:48:27 +08:00
Celestial.y 7abc7c07af Update GitHub Actions to use GraphQL for comments 2025-10-09 21:47:13 +08:00
Celestial.y d8c49a3d04 Test commit on dist-arch 2025-10-09 21:45:07 +08:00
Celestial.y 064bb51d7a Test commit on dist-arch 2025-10-09 21:31:19 +08:00
Celestial.y b74e36ca60 Try to fix workflow 2025-10-09 21:30:43 +08:00
Celestial.y 3e344a3de0 Test commit on dist-arch 2025-10-09 21:26:46 +08:00
Celestial.y b19cc90fd3 Refactor GitHub Actions workflow for discussion comments 2025-10-09 21:26:03 +08:00
clsty eff8d56ef5 Test commit on dist-arch 2025-10-09 21:18:11 +08:00
clsty a0825e7774 Add workflow notify dist-arch update 2025-10-09 21:17:42 +08:00
Celestial.y 765e370bd5 Update dist-gentoo rm opencv 2025-10-09 19:49:53 +08:00
Celestial.y 8469a07f4f Update dist-gentoo rm opencv 2025-10-09 19:48:33 +08:00
Celestial.y fcf4646928 Update scriptdata/uv/README.md
I hope this is the last commit for this file recently.
2025-10-09 19:43:31 +08:00
Celestial.y f5bbb1747c Update scriptdata/uv/README.md 2025-10-09 19:29:17 +08:00
Celestial.y 1868bffbef Update scriptdata/uv/README.md 2025-10-09 19:24:24 +08:00
jwihardi eb5c6796ae Delete dist-gentoo/illogical-impulse-hyprland/things 2025-10-08 18:32:44 -04:00
darksignal7 a35d128bb5 fix: cookie quote shadow color 2025-10-08 23:45:00 +03:00
darksignal7 74787f8927 center the cookie quote correctly 2025-10-08 23:34:32 +03:00
darksignal7 64455b594b add cookie quote again (you can revert this if you dont want) 2025-10-08 23:30:21 +03:00
darksignal7 aa064fb6c5 fix: 'bubble' date indicator start animation not working 2025-10-08 22:21:50 +03:00
darksignal7 70f3a25798 add animation to 'rect' date style 2025-10-08 21:16:14 +03:00
darksignal7 19230db8b7 fix 'rect' date z layer problem 2025-10-08 20:30:30 +03:00
darksignal7 4fb7f7c1e7 'rect' date respects 'numbers' dial style position 2025-10-08 20:10:21 +03:00
jwihardi 0b20dda56e Merge branch 'end-4:main' into main 2025-10-08 12:05:34 -04:00
darksignal7 5c29ac8d1e 'rotating' date also respects timeIndicators 2025-10-08 19:05:34 +03:00
darksignal7 eeed075be2 make 'numbers' dial and 'rotating' date respect each other on position 2025-10-08 19:00:21 +03:00
darksignal7 6c23d482dd refactor 'rotating' date indicator with repeater/text 2025-10-08 18:53:45 +03:00
Celestial.y b2a7b191cf Update scriptdata/uv/README.md 2025-10-08 23:00:10 +08:00
Celestial.y 95c3cf2c90 Update scriptdata/uv/README.md 2025-10-08 22:55:04 +08:00
Celestial.y 26dc81fc6d Update scriptdata/uv/README.md 2025-10-08 22:51:59 +08:00
Celestial.y 26bab59886 Fix example in scriptdata/uv/README.md 2025-10-08 22:43:15 +08:00
Celestial.y c412090dbc Update scriptdata/uv/README.md 2025-10-08 22:25:47 +08:00
end-4 a4c2bf31c7 use python venv for opencv python scripts (#2143) 2025-10-08 10:01:20 +02:00
jwihardi 5d15ccae9f typo in keywords 2025-10-08 01:43:31 -04:00
jwihardi 63f1954c2a ensure eselect-repository installed and updated checking if guru is enablede 2025-10-07 21:29:58 -04:00
clsty 1fc4b88784 Update comment 2025-10-08 05:56:05 +08:00
clsty aa9b1c3331 Fix weird character causing git take it as binary 2025-10-08 05:53:41 +08:00
Celestial.y 458b086468 Update 1.install-deps-selector.sh 2025-10-08 04:17:15 +08:00
jwihardi 75762e8ddd cp needed sudo 2025-10-07 16:16:03 -04:00
jwihardi 58dbdd5189 fixed typos in useflags 2025-10-07 15:50:47 -04:00
jwihardi 0d3d38a032 updated useflags 2025-10-07 15:43:21 -04:00
darksignal7 68ea59328e change 'rotating' dateStyle radius, fix bubble dateStyle 2025-10-07 21:46:40 +03:00
darksignal7 f74a4f056e refractor each date indicator to a new file 2025-10-07 20:13:37 +03:00
end-4 d70e5c396f date indicator: put each style in a loader 2025-10-07 17:43:37 +02:00
end-4 c70b8f7aa2 fix unqualified access in HourHand 2025-10-07 17:33:18 +02:00
end-4 737dd01c8d make MinuteHand not rely on cascading 2025-10-07 17:31:07 +02:00
end-4 945deafa63 MinuteMarks: resolve some unqualified access 2025-10-07 17:30:43 +02:00
end-4 a77b7f7b66 make MinuteMarks not rely on cascading 2025-10-07 17:24:22 +02:00
end-4 e86a0e23bb remove weird transparency 2025-10-07 16:59:06 +02:00
Celestial.y 6218ffabca Add importance of venv to uv/README.md 2025-10-07 22:42:03 +08:00
Celestial.y 4de3c5e587 Update README.md
This also fixes net::ERR_CONNECTION_RESET for the area blocking github.io
2025-10-07 17:28:12 +08:00
end-4 7dc448938a readme: remove "wiki down" notice 2025-10-07 09:38:54 +02:00
end-4 1c30330faf hyprland: remove fcitx5 exec (#2141) 2025-10-07 09:27:33 +02:00
end-4 40d36c2468 hyprland: env: remove input method env vars (#2141) 2025-10-07 09:23:01 +02:00
end-4 d60113bab9 move fcitx5 config to extras (#2141) 2025-10-07 09:02:08 +02:00
end-4 71a19a86f8 readme: show installation steps with manual cloning 2025-10-07 08:52:39 +02:00
clsty 5385a4834a Use venv for python script 2025-10-07 14:51:45 +08:00
clsty 91b55ad2af Increment rN for dist-gentoo 2025-10-07 14:32:10 +08:00
clsty b1428b34c1 Rm kde-material-you-colors-main from dist-gentoo 2025-10-07 14:25:54 +08:00
Celestial.y 3a5b0af81d Remove kde-material-you-colors from deps-info.md 2025-10-07 13:45:03 +08:00
Celestial.y 1f1a9a0b13 Update scriptdata/uv/README.md 2025-10-07 13:44:21 +08:00
Celestial.y 83c9f98d0a Fix typo 2025-10-07 13:42:27 +08:00
Celestial.y c8f8c85c6e Update scriptdata/uv/README.md 2025-10-07 13:41:51 +08:00
Celestial.y 0c14112d60 Update scriptdata/uv/README.md 2025-10-07 13:22:36 +08:00
Celestial.y aa15572c68 Add README for Python package management
Added instructions for managing Python packages and using virtual environments.
2025-10-07 13:16:11 +08:00
clsty b16e171619 Use uv to install kde-material-you-colors instead
(#1533)
2025-10-07 10:57:46 +08:00
Celestial.y a23551c7f2 Add deps-info.md 2025-10-07 09:57:17 +08:00
clsty 95c2947d4a Add comment. 2025-10-07 08:25:00 +08:00
clsty a87e4ff449 Not backup Steam
This is far from perfect because ideally it should only backup the
possible overwritten destinations.
2025-10-07 08:07:52 +08:00
clsty 8fac9fe67e Add link to commit history online 2025-10-07 07:11:14 +08:00
clsty eafaf78c12 Add warning_rsync() for #2133 2025-10-07 06:59:01 +08:00
end-4 66e40128f8 contributing: add some notes about code 2025-10-06 22:42:10 +02:00
darksignal7 cf303380b6 remove 'rotating' animation (it was ugly imo) 2025-10-06 23:07:55 +03:00
darksignal7 4b6b27a8fd add animation to 'rotating' date style 2025-10-06 23:05:03 +03:00
darksignal7 48f054c809 change classic minuteHand anim 2025-10-06 22:50:46 +03:00
darksignal7 10e25fcd03 fix z layer on timeColumn 2025-10-06 22:24:49 +03:00
darksignal7 35dadbb7c4 add animation to stroke hour hand 2025-10-06 19:53:17 +03:00
darksignal7 29bb41aff0 fix hourHand color (again) 2025-10-06 19:47:09 +03:00
darksignal7 28e6da1bbc fix hourHand color 2025-10-06 19:35:11 +03:00
darksignal7 b9a92507d1 fix right bubble show month number 2025-10-06 19:30:09 +03:00
darksignal7 fc8985b242 animate date bubbles with MaterialCookie on constantlyRotate 2025-10-06 19:25:46 +03:00
darksignal7 924a01bca6 fix the animation when changing clock's side count 2025-10-06 19:01:53 +03:00
darksignal7 fac79c8a7d Dont deselect certain date indicators when selecting specific date styles 2025-10-06 18:48:40 +03:00
darksignal7 0e89e8dcc2 make rotating date indicator rotate with secondHand 2025-10-06 18:41:45 +03:00
darksignal7 594dc64824 change rect date animation and background color 2025-10-06 18:32:02 +03:00
end-4 79ec382b7f osk: fix close button making it not openable again 2025-10-06 16:22:43 +02:00
darksignal7 1ec94aa2a6 make constantlyRotate, rotate in clockwise 2025-10-06 17:08:15 +03:00
darksignal7 70a5343d60 revert back bubble colors 2025-10-06 17:04:58 +03:00
end-4 d88da39fe9 cheatsheet: fix misaligned keybind description 2025-10-06 14:43:26 +02:00
end-4 5f369a511a keybinds: add submap to disable keybinds for vms 2025-10-06 14:37:24 +02:00
Celestial.y afac62e788 Update dist-gentoo/README.md 2025-10-06 19:16:55 +08:00
Celestial.y e4533cc03f Update dist-gentoo/README.md 2025-10-06 19:07:31 +08:00
clsty ee9c4baa9d Remove manual installation from README
No one should actually use it,
considering how complex dist-arch/ is.
2025-10-06 17:16:54 +08:00
end-4 27c36530cb date indicator: use expressive font for bubble date 2025-10-06 10:26:07 +02:00
end-4 a5b80c1c73 there must be a space before { 😭💢 2025-10-06 10:15:46 +02:00
end-4 d6e9e9f2a5 less weird no text selection buttons 2025-10-06 10:09:19 +02:00
end-4 122c1f8e37 make TimeColumn not rely on autocascade, rename centerGlow -> hourMarks 2025-10-06 10:09:06 +02:00
end-4 07a3edf020 move more stuff out of cookie clock file 2025-10-06 09:31:39 +02:00
clsty 299fd4f107 Minor updates about information 2025-10-06 10:01:17 +08:00
clsty 1ae989c0c0 Update dist-gentoo 2025-10-06 07:34:55 +08:00
Celestial.y 4d9323800b Gentoo Install (#2116) 2025-10-06 07:26:25 +08:00
jwihardi e935976c91 Update README to include author information 2025-10-05 18:35:49 -04:00
jwihardi 319680e7cc updated init system error message 2025-10-05 18:33:57 -04:00
jwihardi aa40185058 Update README with tty1 service start instructions
Added instructions for starting services after logging into tty1 using Fish shell.
2025-10-05 18:29:46 -04:00
jwihardi d0e0716221 fixed typo 2025-10-05 18:13:54 -04:00
jwihardi 62e6641480 Create README.md for Gentoo dot-files
Added README.md with installation and setup instructions for Gentoo dot-files.
2025-10-05 18:08:40 -04:00
jwihardi 6c25cc6a78 Merge branch 'end-4:main' into main 2025-10-05 17:43:30 -04:00
jwihardi ec3ac73def added GCC warning print 2025-10-05 17:42:19 -04:00
end-4 9b547d6ece bg clock: move date indicator to new file 2025-10-05 22:20:44 +02:00
end-4 ce1f149547 Merge branch 'main' of https://github.com/darksignal7/dots-hyprland 2025-10-05 21:59:58 +02:00
end-4 394d992b19 bg clock: make number column not look goofy 2025-10-05 21:59:54 +02:00
end-4 b8b3b7993b refractor second hand to new file 2025-10-05 21:59:16 +02:00
darksignal7 915877eba6 fix readability (i hope) 2025-10-05 22:50:55 +03:00
end-4 7dda10629a background clock: refractor hour hand and minute hand to new file 2025-10-05 21:38:03 +02:00
end-4 fc5a5d7f63 fix not being able to use dial dots with date 2025-10-05 21:32:06 +02:00
darksignal7 d2ff23813d fix constantlyRotate breaking side ring count 2025-10-05 22:15:36 +03:00
end-4 06840c6c84 settings: fix weird hidden text of clock indicator 2025-10-05 21:13:26 +02:00
end-4 fda70b0aef add second precision option to settings, make cookie clock use DateTime.clock 2025-10-05 21:02:01 +02:00
end-4 7b13ddcbfc remove quote from cookie clock 2025-10-05 20:49:48 +02:00
end-4 741af0fc43 Merge branch 'main' of https://github.com/darksignal7/dots-hyprland 2025-10-05 20:47:51 +02:00
end-4 abf9b6c5e4 Merge branch 'main' of https://github.com/darksignal7/dots-hyprland 2025-10-05 20:47:26 +02:00
darksignal7 56361dda86 using font in appearance 2025-10-05 21:45:10 +03:00
end-4 d276e7b568 settings: remove redundant enableds 2025-10-05 20:43:13 +02:00
darksignal7 5af0fe35df change the place of the showQuote 2025-10-05 21:40:56 +03:00
darksignal7 94fb563a15 fix weird gaps and indents in InterfaceConfig 2025-10-05 21:39:51 +03:00
end-4 865e8575b2 Revert "remove visible's in config"
This reverts commit 20e1fa935a.
2025-10-05 20:37:15 +02:00
darksignal7 d95147712b readd visible's correctly 2025-10-05 21:36:42 +03:00
darksignal7 20e1fa935a remove visible's in config 2025-10-05 21:34:33 +03:00
darksignal7 f885351464 remove animatedSides, use frameAnimation 2025-10-05 21:33:19 +03:00
darksignal7 33fdc1cdc7 set showQuote false by default 2025-10-05 21:27:01 +03:00
end-4 9d39417142 rename waveAnimation to constantlyRotate, disable by default 2025-10-05 20:19:36 +02:00
end-4 96ed90e2cc add time second precision config option 2025-10-05 20:14:57 +02:00
darksignal7 f99c390a76 fix note being visible on digital clock 2025-10-05 20:57:08 +03:00
darksignal7 fba3a54f82 add a note to date styles 2025-10-05 20:51:02 +03:00
darksignal7 fedeb47dbc make bubble date style work with others 2025-10-05 20:46:28 +03:00
darksignal7 79ac51a1ca add new date style (bubble) 2025-10-05 20:35:24 +03:00
darksignal7 02631da9f1 add hiding animation to hands 2025-10-05 20:07:03 +03:00
darksignal7 692172d57b new classic hand style , settings layout change (are there any better ways?) 2025-10-05 20:02:20 +03:00
darksignal7 8bd4bbe7ea add ability to hide minute and hour hand 2025-10-05 19:24:29 +03:00
zoe chen 0d93f90c62 Use thumbnail or wallpaper for Appearance 2025-10-05 23:51:34 +08:00
darksignal7 3f9459a07e fix centerGlow animation 2025-10-05 17:19:49 +03:00
darksignal7 19d063c3e9 fix second dot/hand animation 2025-10-05 17:17:21 +03:00
darksignal7 7f8a5315c4 make code more readable 2025-10-05 17:10:59 +03:00
darksignal7 0f7f7d997b seperate waveAnimation from the materialCookie component 2025-10-05 16:49:47 +03:00
darksignal7 ab54a24434 make center glow active on full dial style 2025-10-05 16:43:13 +03:00
darksignal7 77901659e5 add a lil animation when changing hour hand style 2025-10-05 16:39:25 +03:00
darksignal7 b3f74b6c1c change date color 2025-10-05 16:22:12 +03:00
darksignal7 7eb5fa8d8e add hour hand style 2025-10-05 16:17:37 +03:00
darksignal7 a90e2132e3 add new dial style 2025-10-05 15:57:01 +03:00
darksignal7 60b0db7120 lil tweaks 2025-10-05 14:13:13 +03:00
darksignal7 af538950a8 a lil font change 2025-10-05 13:49:39 +03:00
darksignal7 5787e95c51 add new date style and bunch of new animations 2025-10-05 13:38:53 +03:00
Sighthesia 3b3be4b6cb fix error option name 2025-10-05 17:52:23 +08:00
Sighthesia c1fa902189 bar: change shadow to configurable 2025-10-05 17:48:01 +08:00
Sighthesia 31706e2724 config: add floatSytleShadow option 2025-10-05 17:42:25 +08:00
end-4 21d6bcc63e Brightness: brightnessctl target backlight class 2025-10-05 10:27:20 +02:00
end-4 c4ad1a7127 Translation : update zh_CN and en_US (#2124) 2025-10-05 09:51:06 +02:00
clsty 17984344ee Use arg_excludes for rsync 2025-10-05 10:26:43 +08:00
clsty 035a58e7c5 Update comment 2025-10-05 10:05:29 +08:00
Woozepao 646e33e59f Update .config/quickshell/translations/zh_CN.json
Co-authored-by: Celestial.y <celestial.y@outlook.com>
2025-10-04 19:30:19 -05:00
Woozepao 68ddfb0f02 Update .config/quickshell/translations/zh_CN.json
Co-authored-by: Celestial.y <celestial.y@outlook.com>
2025-10-04 19:30:13 -05:00
darksignal7 cd3b8b5bab add icon to date 2025-10-05 03:13:48 +03:00
darksignal7 da88fd4267 minor tweaks 2025-10-05 03:08:39 +03:00
darksignal7 29413fdc8e hide settings when digital clock is selected 2025-10-05 02:24:36 +03:00
darksignal7 c643d26bce add date to clock 2025-10-05 01:55:39 +03:00
woozepao 69d4f32933 update zh_CN.json 2025-10-04 17:52:13 -05:00
woozepao 26154a6cdb update en_US.json 2025-10-04 17:51:57 -05:00
woozepao 7b22553f09 change qsTr to Translation.tr. support translation 2025-10-04 17:51:24 -05:00
darksignal7 9726f0f586 change settings layout, add option for minuteHand and more.. 2025-10-05 01:40:07 +03:00
darksignal7 25f6f09d22 typo fix 2025-10-04 19:54:04 +03:00
darksignal7 3e6a68b472 fix multiline quote 2025-10-04 19:50:51 +03:00
end-4 60e18c4854 hyprland: remove window cycle keybind
interferes with my vm when i don't capture keys
2025-10-04 17:33:10 +02:00
darksignal7 f7633dd61f add secondDot , fix settings layout little more 2025-10-04 18:13:06 +03:00
darksignal7 ae74354140 fixed bad settings layout, still could be better though 2025-10-04 17:48:19 +03:00
darksignal7 b0987b224d added center glow , wave animation etc. 2025-10-04 17:28:30 +03:00
clsty 5ecae9662f Add --skip-allgreeting 2025-10-04 22:26:40 +08:00
darksignal7 0f29869a76 change settings layout a little 2025-10-04 14:58:32 +03:00
darksignal7 67dd730666 add icons to settings 2025-10-04 14:36:30 +03:00
darksignal7 ccaa13fa21 add animation to cookie clock quote 2025-10-04 14:20:02 +03:00
Vague Syntax ff795b1373 Merge branch 'main' into main 2025-10-04 13:58:36 +03:00
end-4 81287e9eb5 settings: more icons 2025-10-04 12:54:34 +02:00
darksignal7 26b9d8193c add settings for clock, add quote for cookie clock, make quote editable from settings 2025-10-04 13:47:40 +03:00
end-4 81bdb352aa overview: fix dragging z index (#2068) 2025-10-04 12:27:16 +02:00
end-4 2ae8530c83 Set background opacity when using live wallpaper (#2114) 2025-10-04 10:30:38 +02:00
end-4 476755fc18 settings: add toggles for lock screen security options 2025-10-04 09:55:57 +02:00
jwihardi 4247495cf4 added init system error message 2025-10-03 21:34:29 -04:00
jwihardi b6eada070a Merge branch 'end-4:main' into main 2025-10-03 21:33:10 -04:00
darksignal7 2399600169 minimize settings 2025-10-04 01:09:25 +03:00
jwihardi db9877beae Delete dist-gentoo/keywords-user 2025-10-03 16:04:02 -04:00
darksignal7 43f1d5c53e finalize simpler cookie clock 2025-10-03 22:38:20 +03:00
jwihardi 4a31d538c6 added liveebuilds 2025-10-03 14:40:51 -04:00
zoe chen 23dd7baf35 Set background opacity when using live wallpaper
It was causing thumbnail to display over mpvpaper
2025-10-04 01:43:32 +08:00
darksignal7 a8e1f3ef4c added simpler cookie clock style 2025-10-03 19:19:21 +03:00
jwihardi cd622e9f81 added gentoo install 2025-10-02 22:43:39 -04:00
end-4 71f7d45084 feat: add hebrew language support (#2099) 2025-10-03 01:06:30 +02:00
end-4 0f586fe49e Update auto-Hypr.fish (#2106) 2025-10-03 01:04:42 +02:00
end-4 42913816ce lock: add option to require password for poweroff/reboot (#2085) 2025-10-03 01:02:03 +02:00
end-4 027f9a1793 hyprlandxkbindicator: don't reference the button out of nowhere 2025-10-03 00:50:35 +02:00
Jojo 8bc2cf335b lock: add reboot button (#2086)
* lock: added reboot button

* lock: reorder reboot/shutdown buttons

---------

Co-authored-by: end-4 <97237370+end-4@users.noreply.github.com>
2025-10-02 23:39:20 +02:00
jwihardi 626c71a942 Merge branch 'end-4:main' into main 2025-10-02 17:06:46 -04:00
Khyretos 58b9c4f1d6 Update auto-Hypr.fish
Autologin fix for fish
2025-10-02 20:52:48 +02:00
Sighthesia 24163dfa4a bar: fix float bar tint loss 2025-10-03 01:34:51 +08:00
clsty e3d596e034 Add TODO in comment 2025-10-03 00:30:18 +08:00
clsty cd48f45462 Del chmod +x in update.sh targeting scriptdata
Although I am not the one creating update.sh,
I am certain that giving execute permission for
scripts under scriptdata/ is wrong cuz
they are not for executing independently,
but for being sourced by other scripts.
2025-10-03 00:10:45 +08:00
clsty a0229e8132 Fix comment. 2025-10-03 00:03:41 +08:00
clsty be7ff94ae3 Fix comment 2025-10-02 23:56:38 +08:00
clsty 98ddce24ad Re-arrange scripts; fix comments in dist-nix 2025-10-02 23:51:59 +08:00
clsty b380a77a7d Add outdate detect logic for dist-<DISTRO-ID> 2025-10-02 20:56:43 +08:00
clsty 9f7a2d86cf No hash, just timestamp 2025-10-02 18:55:33 +08:00
clsty 343a7ef4fe Add git_unshallow and latest_commit_hash 2025-10-02 18:47:14 +08:00
clsty 88c3b0ba83 Remove old ags entries from .gitignore 2025-10-02 16:48:45 +08:00
clsty 918997acfa Rearrange install scripts.
This commit is a preparation for detection about
whether a dist-<DISTRO_ID>/ folder is outdated.
2025-10-02 16:38:43 +08:00
jwihardi dd1fb111a5 updated the script and added unmask file 2025-10-01 22:12:17 -04:00
jwihardi 7124b69912 renamed gentoo-ebuild to gentoo-support 2025-10-01 19:56:55 -04:00
jwihardi 76bcca55d2 Merge branch 'end-4:main' into main 2025-10-01 19:55:06 -04:00
jwihardi 7fa2ffc14e added an installer and use flags 2025-10-01 19:54:04 -04:00
clsty 0ee141493f Improve message. 2025-10-02 07:39:15 +08:00
clsty 194b21c41e Improve message. 2025-10-02 07:26:59 +08:00
clsty 93634985e8 Fix $2100 2025-10-02 07:24:02 +08:00
clsty 6757dc2ca1 Fix $2101 2025-10-02 07:20:25 +08:00
clsty 3a888f9be4 Add pause(); distro specific also for setups 2025-10-02 07:13:51 +08:00
clsty 34c9cbeedb Tweaks for text and names 2025-10-02 05:54:35 +08:00
Ofek 97a2769002 Update translation for 'Silent' in Hebrew 2025-10-01 22:17:59 +03:00
clsty f87e6e2b6a Update message in install-deps.sh 2025-10-02 02:41:48 +08:00
clsty 7bd3f1e08d Update comment. 2025-10-02 02:31:44 +08:00
Ofek Almog aeb20a8949 feat: add hebrew language support 2025-10-01 21:30:44 +03:00
clsty 58e99403ad Add comment. 2025-10-02 02:24:11 +08:00
clsty 530987152c Fix message in uninstall.sh 2025-10-02 02:12:07 +08:00
clsty 4085b4a74a Improve dependency install process 2025-10-02 01:57:20 +08:00
clsty 852172a7ff Add distro and arch detect, add skip options 2025-10-02 00:35:33 +08:00
clsty 7aa1230553 Rename scripts for syntax highlighting 2025-10-01 21:49:46 +08:00
clsty a7097014a3 Quick fix syntax 2025-10-01 21:44:06 +08:00
clsty 9f711c20e0 Use variable to store color for script output 2025-10-01 21:40:06 +08:00
clsty 87c031b825 Rearrange install.sh to split Arch thingy apart 2025-10-01 20:44:25 +08:00
end-4 18e2f5dd7f Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-10-01 08:15:09 +02:00
end-4 d1b70185f1 styledtext: fix letter spacing (#2092) 2025-10-01 08:15:07 +02:00
end-4 254175c98e fix: ignore case (The latest Hyprland process name has changed) (#2087) 2025-10-01 06:36:55 +02:00
jwihardi e8e67912ec Merge branch 'end-4:main' into main 2025-09-30 19:35:49 -04:00
end-4 3c00805763 lock: also unlock keyring on unlock 2025-09-30 23:07:04 +02:00
end-4 599055b49f search: add /wipeclipboard action 2025-09-30 20:47:44 +02:00
end-4 82fa754497 ai: ctrl+v to attach file
note: only convenient with dolphin
2025-09-30 20:47:10 +02:00
cyclesw 9ec9cc0e25 fix: ignore case (The latest Hyprland process name has changed) 2025-10-01 01:36:57 +08:00
end-4 f52c9415c9 fix(brightness): prevent bus number collision for identical monitor m… (#2077) 2025-09-30 08:39:36 +02:00
end-4 27626ee59a ai: simplify auto scroll (#2080) 2025-09-30 07:58:54 +02:00
end-4 0b36e2a833 lock: do not autostart after crash 2025-09-30 07:45:10 +02:00
Kacper Piłsyk 1aa0e3fb47 fix(brightness): prevent bus number collision for identical monitor models 2025-09-29 23:27:28 +02:00
end-4 4a40ce5646 idle inhibitor: only remember toggled state within same session 2025-09-29 22:47:57 +02:00
end-4 6e126dc08d lock: option to launch on startup (#2076) 2025-09-29 22:21:09 +02:00
end-4 6201798ef5 ai: ctrl+shift+o to clear 2025-09-29 10:28:54 +02:00
end-4 ec3c09607d bar: fix misaligned items for horizontal floating mode (#2075) 2025-09-29 08:20:15 +02:00
Sola 2b104435dc fix overview scaling issue 2025-09-29 07:59:42 +08:00
end-4 83be5822b1 add random osu seasonal wallpaper button 2025-09-28 20:50:21 +02:00
end-4 0491bd993e overview: floating window position move 2025-09-28 20:48:59 +02:00
end-4 8713e94428 screenshot tool: make dark overlay clipped by selection, add selection size indicator 2025-09-28 18:44:05 +02:00
end-4 ccab724db2 screenshot tool: fix interactivity of floating windows being behind tiled 2025-09-28 18:16:14 +02:00
end-4 7876ab993a settings: remove unnecessary page check for anim 2025-09-28 18:05:31 +02:00
end-4 bd8e004795 osd: unify brightness and volume 2025-09-28 18:04:57 +02:00
end-4 01ab0f5ab9 cheatsheet: ptable: make elements not look weird when hovered 2025-09-28 16:57:32 +02:00
end-4 0728dba0cd cheatsheet: added element weight to periodic table (#2067) 2025-09-28 16:52:45 +02:00
end-4 3dd5e78b35 overview: force floating windows to be on top of tiling ones (#2068) 2025-09-28 16:43:43 +02:00
nrand 667afa6d64 cheatsheet: added element weight to periodic table 2025-09-28 15:25:59 +03:00
end-4 d24555a4d7 bar: workspaces: no more Layout 2025-09-28 14:25:52 +02:00
end-4 410971a228 scroll hint: no more Layout, add tooltip 2025-09-28 14:14:43 +02:00
end-4 b497c22d6b overview: fewer Layouts 2025-09-28 14:07:50 +02:00
end-4 de6969f561 bar: fix tooltip shadow cutoff, use fewer Layouts 2025-09-28 14:03:18 +02:00
end-4 0ce4260134 background: fewer Layouts 2025-09-28 13:53:27 +02:00
end-4 7237dd053d lock: use Rows instead of RowLayouts 2025-09-28 13:47:40 +02:00
end-4 0f6c076dda use more non-Layouts 2025-09-28 13:42:44 +02:00
end-4 b57e678dc9 notifications: fix ultra laggy expansion 2025-09-28 13:15:23 +02:00
end-4 6031bb4953 left sidebar: consider closed when floating window is closed 2025-09-28 12:05:42 +02:00
end-4 05dc53b396 use StyledImage in more places 2025-09-28 11:52:35 +02:00
end-4 e97f819a5c make night light auto still function after manual toggle (#2030) 2025-09-28 11:33:58 +02:00
end-4 28c37c08d2 make media control seekable (closes #1615) 2025-09-28 10:45:16 +02:00
end-4 f430b22884 fix shadow radius 2025-09-28 10:39:56 +02:00
end-4 cf4505635b toolbar: add make radius configurable 2025-09-28 08:39:59 +02:00
end-4 8ad0de63e1 Fix various issues of overview with multiple monitors setup (#1953) 2025-09-28 08:35:41 +02:00
end-4 8068ea95d5 truncate xkb variants to avoid text overflow (#2032) 2025-09-28 08:26:29 +02:00
end-4 44cbd025f4 correct indentation, remove unnecessary check 2025-09-28 08:25:48 +02:00
jwihardi ac76930dd1 Merge branch 'end-4:main' into main 2025-09-27 00:04:30 -04:00
jwihardi 3a653d9558 renamed folder 2025-09-26 20:03:31 -04:00
jwihardi ae50430527 added gentoo ebuild 2025-09-26 20:02:44 -04:00
end-4 83386bcdbf overviewwidget: fix undefined warning 2025-09-26 23:56:31 +02:00
end-4 1e175e4e82 work safety for clipboard images copied from browser 2025-09-26 23:56:13 +02:00
end-4 01815d04dc remove unused shaders 2025-09-26 23:05:34 +02:00
end-4 46ea6900b4 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-09-26 22:55:21 +02:00
end-4 6394fe049d notifications: prevent summaries from spilling 2025-09-26 22:55:14 +02:00
end-4 f324fc7c10 readme: push unsupported stuff down 2025-09-26 10:21:19 +02:00
end-4 434c383fcd remove deprecated label from ags version, its totally unsupported now 2025-09-26 09:49:49 +02:00
end-4 9eade626aa overview: fix large vertical tooltip padding 2025-09-25 09:49:22 +02:00
end-4 263299b97d SearchItem: fix undefined warnings 2025-09-24 09:25:36 +02:00
end-4 7e491ce7d8 settings: adjust min window size 2025-09-24 09:25:29 +02:00
end-4 6707487d3c background: fix clock movement jumping abruptly 2025-09-24 08:29:04 +02:00
end-4 0498d7ea98 overview: clearer numbers 2025-09-23 21:36:09 +02:00
end-4 fc9bda9f7f add scroll edge fade to some scrolled windows 2025-09-23 11:14:34 +02:00
end-4 2b47083c12 settings, welcome: change konachan btn icon, fix wallpaper desync 2025-09-23 11:14:00 +02:00
end-4 1f700f33b2 cookie clock: put color props to root 2025-09-23 11:13:18 +02:00
end-4 769dafb428 move adapted material scheme to new file 2025-09-23 11:13:00 +02:00
end-4 e3bc2e5d84 more wallpaper safety filters 2025-09-23 11:12:22 +02:00
end-4 f3120f1e0d background: fix cookie clock positioning when locked + wall safety 2025-09-22 21:54:15 +02:00
end-4 036d8b4852 lock: allow centering clock when not blurred 2025-09-22 21:50:25 +02:00
end-4 a67a8d746f background: add scale config option for clock 2025-09-22 21:04:31 +02:00
end-4 2237ec135c background: add cookie clock style 2025-09-22 20:25:46 +02:00
dodaars a238c33fd0 A simple function to slice keyboard variants to avoid overflow of text when using vertical bars
I added a function that slices keyboard variants to be at most 4 characters long to avoid text overflow, especially when you set the bar to be vertical.
2025-09-21 23:54:12 +02:00
end-4 b90cf14228 add random wallpaper keybind 2025-09-21 20:21:34 +02:00
end-4 7bbd1d2d52 fix(ai): Fix JSON injection vulnerability in primary-buffer-query.sh (#1973) 2025-09-21 20:04:15 +02:00
end-4 8aebbb1b51 feat(ai): Add auto-scroll functionality to AI chat (#1972) 2025-09-21 19:51:38 +02:00
end-4 df7504d4a2 remove useless ai comments 2025-09-21 19:51:15 +02:00
end-4 063399a6d6 settings: make crosshair code setting less misleading 2025-09-21 18:57:38 +02:00
end-4 9762a94138 notifications: make icon guesses less strict 2025-09-21 18:57:27 +02:00
end-4 800f5c7c64 background: fix locked text spacing when there is no quote 2025-09-21 13:59:20 +02:00
end-4 16995d2ae5 wallpaper safety 2025-09-21 12:08:09 +02:00
end-4 b4cced68f1 Change SCSS file path emacs theme thingy 2025-09-21 11:03:37 +02:00
end-4 9bb01bba30 update hyprland config for crosshair 2025-09-21 10:37:12 +02:00
end-4 cb3842f0bd implement crosshair 2025-09-21 10:33:25 +02:00
end-4 5d95d20a32 sidebarright: remove unused imports 2025-09-21 10:31:21 +02:00
end-4 b628ee0c3e fix hyprland xkb indicator cant unassign undefined warning 2025-09-21 10:31:10 +02:00
end-4 688bf0bef8 bar: refractor xkb layout indicator 2025-09-20 23:18:41 +02:00
end-4 06d6d3a9ca bar: adjust xkb layout indicator font size 2025-09-20 13:05:23 +02:00
end-4 bb4debb863 bar: fixed kb layout+variant display in top right (#2016) 2025-09-20 13:02:49 +02:00
end-4 5d1a3fe6a7 hyprland xkb layout indicator: fix weird placement on vertical bar 2025-09-20 13:02:18 +02:00
end-4 72b5d006ba vertical bar: make tray tooltips not cut off 2025-09-20 12:47:04 +02:00
end-4 d382358766 bar: tray: make action trigger on press 2025-09-20 12:40:58 +02:00
end-4 429cb50ff7 tooltips: use builtin text prop, fix crash (#1956) 2025-09-20 11:55:38 +02:00
end-4 3a01dad945 aloow configuration of notif timeout duration 2025-09-20 10:47:09 +02:00
end-4 b9ae5cafa0 brightness: delay setting for ddc monitors (#2022) 2025-09-20 10:37:24 +02:00
end-4 ed8e4b8766 move some files placed in the wrong folder 2025-09-20 10:11:35 +02:00
end-4 cecd47caea make filled symbols suck less 2025-09-20 10:08:02 +02:00
end-4 7711946cf5 bar: remove unused imports 2025-09-20 09:50:15 +02:00
end-4 074aebbe5d tray: fix checkbuttons' clickability in menus 2025-09-20 09:49:57 +02:00
end-4 8b78d05805 background: fix clock position 2025-09-20 09:49:34 +02:00
end-4 cf962a26f4 workspaces: fix some undefined thingy 2025-09-20 09:31:26 +02:00
end-4 14778696e9 custom system tray 2025-09-20 09:30:17 +02:00
nrand ed56d03c09 bar: actually fixed it (there was a typo oopsie) 2025-09-19 07:58:12 +03:00
end-4 f9d9df4bbf lock screen blur: fix center clock option, add settings app toggles 2025-09-18 14:07:21 +02:00
nrand 0859d75256 bar: fixed kb layout+variant display in top right 2025-09-18 15:03:41 +03:00
end-4 21303b24c8 welcome app: add tip for window close keybind 2025-09-18 08:18:10 +02:00
end-4 06965e7eed Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-09-18 08:13:07 +02:00
end-4 fc0b069ad2 media: progress update interval follows resources 2025-09-18 08:12:52 +02:00
end-4 b0b27d6842 feat(sideright): add Flatpak support for EasyEffects service and toggle (#2013) 2025-09-18 08:08:44 +02:00
end-4 47725ea4b5 bar: fix autohide's hover region not working on hyprland 0.51 (#1994) 2025-09-18 07:52:08 +02:00
0blivi0nis 103d349c5f feat(sideright): add Flatpak support for EasyEffects service and toggle 2025-09-17 23:49:45 +00:00
end-4 c41364fb16 lock: rename bg blur config option, no blur by default 2025-09-17 23:39:56 +02:00
end-4 b984d6794e wallpaper selector: fix thumbnail generation (#1978, #1902) 2025-09-17 11:35:42 +02:00
end-4 cf4aa1256d wallpaper selector: make quick dir icon filled when selected 2025-09-16 08:32:07 +02:00
end-4 4a6fcb4f4c wallpaper selector: hide Homework folder if not weeb, fix toolbar button alignment 2025-09-16 08:30:30 +02:00
end-4 426804304c wallpaper selector: add random button (#1997) 2025-09-16 08:22:47 +02:00
end-4 074f8ed902 wallpaper selector: allow making system picker the default 2025-09-15 21:52:58 +02:00
end-4 d3a1bd52c7 more readable terminal colors by default 2025-09-15 21:51:42 +02:00
end-4 a4103859cd lock: hide color overlay when unlocking in light mode 2025-09-15 08:32:04 +02:00
end-4 ed19b7b635 lock screen: blur effect, better anims 2025-09-14 22:53:55 +02:00
end-4 f21dd041ae add StyledBlurEffect 2025-09-14 22:46:35 +02:00
end-4 2de21b5f25 tray: hide "passive" items (#1987) 2025-09-14 21:05:17 +02:00
end-4 a547ae6cf9 hyprland dead edge problem: use old hyprland hotspot padding 2025-09-13 22:55:18 +02:00
end-4 c39901e95d icon guessing: add quickshell's heuristic lookup 2025-09-13 22:13:43 +02:00
end-4 4f0522d913 idle inhibitor: use quickshell instead of pythong script 2025-09-13 22:03:03 +02:00
end-4 b972d3fabe Translation : update zh_CN.json (#1975) 2025-09-13 09:33:07 +02:00
czn d6bef6b17d Translation : update zh_CN.json 2025-09-12 22:22:07 +08:00
czn 231100cbdc Translation : update zh_CN.json 2025-09-12 21:50:24 +08:00
end-4 9c8d71ca4d wallpaper selector: back/forward navigation 2025-09-12 08:09:12 +02:00
end-4 fcdc17dd93 dead pixel workaround: also for bottom edge 2025-09-12 08:08:39 +02:00
Gwendolyn Page a719ca684c fix(ai): Fix JSON injection vulnerability in primary-buffer-query.sh
- Fix critical JSON injection vulnerability by properly escaping clipboard content using jq
- Add content length limiting (2000 chars) to prevent overflow attacks
- Use proper JSON payload construction with jq to ensure safe API calls
- Add silent curl flag and error handling for reliability

This addresses a security issue where malicious clipboard content could break
out of JSON strings and potentially execute arbitrary code.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-11 17:49:10 -05:00
Gwendolyn Page e5033c3213 feat(ai): Add auto-scroll functionality to AI chat
- Add shouldAutoScroll property to track when user wants auto-scrolling
- Auto-scroll when user sends a message to see the response
- Auto-scroll during streaming when content height changes
- Auto-scroll when new messages are added to the conversation
- Stop auto-scroll when user manually scrolls up (preserves user intent)
- Resume auto-scroll when user scrolls back to bottom

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-11 17:20:28 -05:00
end-4 d37cf9e9c4 fix(brightness): use the monitor's max brightness instead of '100' (#1966) 2025-09-11 23:28:29 +02:00
end-4 d9688884e4 Rename maxBrightness to rawMaxBrightness
less confusing because `brightness` is percentage
2025-09-11 23:27:14 +02:00
end-4 2f369bbf3d fix setting brightness with brightnessctl 2025-09-11 23:25:06 +02:00
end-4 7f1b67d21c lock: hide battery display on desktops 2025-09-11 19:31:43 +02:00
end-4 6118589248 workaround for hyprland's 1px dead right edge 2025-09-11 15:48:44 +02:00
Emmmmllll 9a7f5c2def fix(brightness): use the monitor's max brightness instead of '100' 2025-09-11 14:26:38 +02:00
end-4 1999f17443 wallpaper selector: fix incorrect address bar 2025-09-11 10:03:34 +02:00
end-4 7e39f0a34f bar: make tray items pinned by default 2025-09-11 09:59:05 +02:00
end-4 fb9a726ba0 bluetooth dialog: sort names before mac addresses 2025-09-11 09:48:13 +02:00
end-4 ddc3f0e880 hyprland: add window move and overview gestures 2025-09-11 08:46:46 +02:00
end-4 d66b0891e7 hyprland: adapt new gesture config (#1892) 2025-09-11 07:48:48 +02:00
cupcat121 f1ba087bff fix wrong monitor data being passed to OverviewWindow 2025-09-11 00:29:44 +08:00
end-4 6cf5f2edc4 RoundCorner: remove unnecessary and not properly imported anim 2025-09-09 21:38:08 +02:00
end-4 f0570b0e20 fix kb layout anim in lock screen (#1942) 2025-09-09 20:34:49 +02:00
cupcat121 cd851afc8d remove TODO 2025-09-09 19:08:29 +08:00
cupcat121 532497f6bd fix out of index error in OverviewWindow monitorData 2025-09-09 14:14:34 +08:00
end-4 f648137a8e hyprland: not have redundant lid close suspend keybind bind (fixes #1929) 2025-09-08 23:27:00 +02:00
end-4 e9fd2f89fe StyledText: fix text being offset with rapid change (#1942) 2025-09-08 23:13:43 +02:00
end-4 5565911e2c battery: prevent auto suspend due to low bluetooth batt (#1882) 2025-09-08 23:07:52 +02:00
end-4 7337012280 background: no smoothing 2025-09-08 22:36:24 +02:00
end-4 e3f25e3bc4 Feat: Add option to enforce dark mode for the terminal (#1945) 2025-09-08 22:35:14 +02:00
cupcat121 9582a473c6 revert applycolor.sh and rewrite the main logic 2025-09-08 20:24:06 +08:00
cupcat121 22918e4b4a move config to terminalGenerationProps 2025-09-08 18:46:52 +08:00
cupcat121 0d567ea5dc Merge remote changes 703697e1 2025-09-08 18:01:59 +08:00
end-4 703697e1c4 settings & welcome: add icons to policies 2025-09-08 09:18:09 +02:00
end-4 0b89ed0d17 tray: use more descriptive text for tooltip and update on entry (#1906) 2025-09-08 09:13:05 +02:00
Moeta Yuko f3de317ddd tray: use more descriptive text for tooltip and update on entry
The systray id is intended for programmatic use rather than frontend
presentation. It is recommended to use the tooltipTitle and title
attributes when available, and these should be updated upon entry, as
their values may change dynamically.
2025-09-08 14:46:42 +08:00
end-4 cd7e60b7a1 hyprland: make snapping gap consistent with tiling gap 2025-09-08 08:40:18 +02:00
end-4 352a5bea5c Make window snap respect window gaps (#1950) 2025-09-08 08:37:09 +02:00
end-4 f33eaf6d0f settings: add advanced terminal color generation props 2025-09-07 22:53:18 +02:00
end-4 81ebf9cc11 settings: move some settings to new "general" tab 2025-09-07 22:33:41 +02:00
end-4 23f92e0a96 hyprland: more blur noise 2025-09-07 22:28:27 +02:00
kxrur e69f8ced88 make snap repsect window gaps 2025-09-07 13:31:05 -04:00
end-4 ba5b052ee8 readme: add note about availability of installation methods n stuff 2025-09-07 09:39:13 +02:00
end-4 b6e6997e7c Customize harmony values for colors from wallpaper (#1910) 2025-09-06 10:38:33 +02:00
end-4 c39507747b rename generationProps -> terminalGenerationProps, change default harmony to match script 2025-09-06 10:38:15 +02:00
end-4 c9f4390f0f Feature: Hide online models on local ai policy (#1784) 2025-09-06 10:20:08 +02:00
end-4 801cd2e855 only show konachan button and create homework folder when weeb 2025-09-06 09:44:46 +02:00
end-4 e9c73ebb71 readme: update ii-qs showcase 2025-09-06 09:23:03 +02:00
end-4 6af3a1b5a7 (vertical) bar: refractor workspaces 2025-09-06 08:44:39 +02:00
end-4 c86dbeb2b3 lock: key presses also reset inactivity timer 2025-09-06 08:44:25 +02:00
cupcat121 4ff6b2a30a update en_US translation 2025-09-06 12:21:07 +08:00
cupcat121 3310d2b431 update zh_CN translation 2025-09-06 12:07:20 +08:00
cupcat121 b53de43c95 add forced theming mode for terminal 2025-09-06 12:07:20 +08:00
cupcat121 ffb8e284b4 add config to force terminal theming mode 2025-09-06 12:07:19 +08:00
end-4 f593ad0f2c make selection buttons less weird with cjk 2025-09-05 23:34:50 +02:00
end-4 9114d5b2fe NavigationTabArray: fix undefined warning 2025-09-05 23:34:40 +02:00
end-4 5b47a20d49 scrollbar: add to stuff, adjust draggable spacing 2025-09-05 23:34:20 +02:00
end-4 b0acc5a68e translations: make language change happen live 2025-09-05 23:31:08 +02:00
end-4 d7382db669 ai: fix chat.json doesn't exist warning 2025-09-05 21:17:01 +02:00
end-4 f290192de4 disable earbang protection by default 2025-09-05 20:30:18 +02:00
end-4 8360d4d589 animate xkb layout indicator change 2025-09-05 14:54:21 +02:00
end-4 df56224df6 lock screen: add kb layout indicator 2025-09-05 13:07:44 +02:00
end-4 1a636ff8e9 clock tooltip: not show redundant time 2025-09-05 13:06:44 +02:00
end-4 4dcc1f340f lock: animate left pill appearance too 2025-09-05 08:08:43 +02:00
end-4 f199bc4256 lock screen: battery level 2025-09-05 08:05:52 +02:00
end-4 11e28286e1 lock: fix sleep button color 2025-09-05 07:53:37 +02:00
end-4 4c454d463a fish: move setups to interactive shell 2025-09-03 11:51:25 +02:00
end-4 80034d8658 background: add auto vertical parallax option 2025-09-02 19:57:17 +02:00
end-4 296afa96c6 wallpaper selector: dont cache thumbnails 2025-09-02 19:50:15 +02:00
end-4 9f69b8815a settings: more icons 2025-09-01 22:19:16 +02:00
end-4 cdc38f7e6e settings: redesign home page 2025-09-01 18:05:45 +02:00
end-4 fcb4e6cc85 bar: always show cpu usage by default 2025-09-01 18:05:14 +02:00
end-4 cb00f31f79 readme: no more ags support 2025-09-01 13:47:13 +02:00
end-4 84c65d32be add dolphin config 2025-09-01 11:17:53 +02:00
end-4 cc119bb596 add darkly config 2025-09-01 11:13:13 +02:00
end-4 88c9850073 settings: make pages fly up 2025-09-01 11:05:00 +02:00
end-4 75fcb9a990 welcome app: add tip for broken color changing 2025-09-01 10:51:10 +02:00
end-4 7121a4ae30 disable transparency by default (why was this even on...) 2025-09-01 08:39:10 +02:00
end-4 e636920c44 search: clipboard: nicer delete button, add copy button 2025-08-31 17:57:16 +02:00
end-4 e0cf3d0962 notifications: add group expand tip tooltip 2025-08-31 17:29:06 +02:00
end-4 53b6f5d8e8 add superpaste 2025-08-31 17:21:55 +02:00
Souyama 5acbfac255 terminals harmony pass into args 2025-08-31 19:59:52 +05:30
Souyama 82bb1175bd customize terminals harmony 2025-08-31 19:57:49 +05:30
end-4 f1b1589a7d use JetBrains Mono instead of SpaceMono for nerd font 2025-08-31 14:35:17 +02:00
end-4 0f4ff90f01 add setting to show/hide the clock in background (#1881) 2025-08-31 13:06:16 +07:00
end-4 43e0bcbf73 Merge branch 'main' into background-clock-setting 2025-08-31 13:05:04 +07:00
end-4 e26045ec73 background: clock size: safer access 2025-08-31 08:04:23 +02:00
end-4 2d52680bed make time correct after waking up from suspend (fixes #1905) 2025-08-31 07:56:12 +02:00
end-4 f42f526f93 fix more bluetooth warning 2025-08-31 07:54:46 +02:00
end-4 53b03af3e1 wifi menu: fix undefined warnings 2025-08-30 22:14:32 +02:00
end-4 32f8692f13 toolbar: adjust spacing 2025-08-30 22:10:47 +02:00
end-4 19c321e7ae wallpaper selector: progress indicator for thumbnail generation 2025-08-30 22:10:29 +02:00
end-4 021a49a72d wifi & bluetooth dialogs: indeterminate progressbar while scanning 2025-08-30 22:09:05 +02:00
end-4 eb0bad1af6 wallpapers: add fallback magick thumbnailer script 2025-08-30 17:47:37 +02:00
end-4 513d140ea2 wallpaper selector: paste directory/file to navigate 2025-08-30 16:39:13 +02:00
end-4 3e368141c7 bluetooth menu: round battery level 2025-08-30 15:54:11 +02:00
end-4 b59b7c1e47 bar: add workspace number mapping (#1886) 2025-08-30 20:03:16 +07:00
end-4 6a1acc819b workspace numbers: allow using nerd font 2025-08-30 15:01:59 +02:00
end-4 e5db36e21e workspace number mapping: rename config var, use list 2025-08-30 14:59:11 +02:00
end-4 d759bc274f bluetooth menu: right click to expand item 2025-08-30 14:34:32 +02:00
end-4 3290755fa8 wallpaper selector: correct search box placeholder 2025-08-30 09:28:11 +02:00
end-4 fd3455d3ec wallpaper selector use Toolbar for name filter 2025-08-30 09:09:05 +02:00
end-4 88355b2504 lock: use default pam config and start without password (#1891) 2025-08-30 13:52:25 +07:00
end-4 79f078653a bluetooth menu: stop scanning when closed, fix null warnings 2025-08-30 07:55:29 +02:00
end-4 a952ea02dc bluetooth menu 2025-08-30 07:51:18 +02:00
end-4 59abffb1c1 background: fix empty space between clock and lock text 2025-08-30 07:48:21 +02:00
Moeta Yuko d737139bee hyprland: adapt new gesture config 2025-08-29 16:08:55 +08:00
Moeta Yuko a1479a9b6c lock: use default pam config and start without password
Fixes #1800
2025-08-29 15:55:36 +08:00
kirisaki-vk 45894c3255 chore: use var instead of list 2025-08-29 09:51:08 +03:00
end-4 dcfdb2ecff Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-08-29 08:16:53 +02:00
end-4 ba7ed5be1c background: fix quote not working 2025-08-29 08:03:01 +02:00
end-4 307412e6ca fix: improve Japanese translations for clarity and consistency (#1889) 2025-08-29 12:40:01 +07:00
end-4 41e1e89696 sidebar: wifi menu: public wifi login page button 2025-08-29 07:29:14 +02:00
end-4 d239ab6b1f bluetooth: refractor and fix wrong icon 2025-08-29 12:06:01 +07:00
rain022 0905773d08 I've made a slight adjustment to the nuance.
It should be fine to merge now.
2025-08-29 05:43:18 +09:00
rain022 9ca80d352b fix: improve Japanese translations for clarity and consistency 2025-08-29 04:38:12 +09:00
end-4 b52440bcc1 media controls: outside click dismissal, no player placeholder 2025-08-28 18:17:11 +07:00
kirisaki-vk 28c9cacf68 bar: add workspace number mapping 2025-08-28 09:30:54 +03:00
hoovad 8199fdd2bf fix undefined error 2025-08-27 19:13:21 +02:00
end-4 f74ed76850 cheatsheet: use slide anim 2025-08-27 22:00:48 +07:00
end-4 5b301addd8 feat: add wallpaper selector menu (#1820) 2025-08-27 21:56:50 +07:00
end-4 1c1a141701 wallpaper selector: freedesktop spec-compliant thumbnail generation 2025-08-27 21:51:15 +07:00
end-4 e85f59db8c remove useless comments 2025-08-27 20:18:17 +07:00
end-4 fc69ca0599 sidebar: wifi dialog: esc to close 2025-08-27 20:13:46 +07:00
end-4 2ad304aaf2 config: rename "mantra" to "quote" 2025-08-27 20:13:19 +07:00
end-4 c1b56922aa sidebar: refractor wifi dialog to new file, make it dynamically loaded 2025-08-27 18:30:58 +07:00
end-4 8c737f2ca4 quickshell: fix some warnings 2025-08-27 17:59:35 +07:00
end-4 20d9561143 wifi menu 2025-08-27 17:52:23 +07:00
hoovad 1062ef9b49 move anchors to Loader, remove unnecessary visible and move setting 2025-08-27 06:04:13 +02:00
hoovad 2b54f64c8c use camelCase and unload instead of hiding 2025-08-27 05:30:15 +02:00
hoovad 5cd5a9d7e4 add setting to show/hide the clock in background 2025-08-27 05:01:42 +02:00
end-4 bb49747fd9 bluetooth: use quickshell's service 2025-08-26 21:50:37 +07:00
end-4 f38c7bffed network: implement toggling in service 2025-08-26 21:07:00 +07:00
end-4 813f02604e network: no more polling, fix sidebar toggle enabled state 2025-08-26 20:56:32 +07:00
end-4 c579dce2cf background: fix wallpaper being offscreen depending on aspect ratio 2025-08-26 19:52:21 +07:00
end-4 f6d9c2998b background: add back PreserveAspectCrop fillMode (#1879) 2025-08-26 19:20:31 +07:00
end-4 60c303b771 background: add padding for clock text in least busy region detection 2025-08-26 18:00:06 +07:00
end-4 79e7f262a7 lock screen: redesign password prompt 2025-08-26 17:59:37 +07:00
end-4 8f2863c02c background: fix blurry background when scaled 2025-08-26 15:29:20 +07:00
end-4 cd8cb03797 settings: prevent race condition of wallpaper zoom spinbox 2025-08-26 14:39:11 +07:00
end-4 9f4aa3f7e1 add corner scrolling for brightness/volume 2025-08-26 14:38:37 +07:00
end-4 eb2c9f2fe1 wallpaper selector: adjust size and item colors, fix address bar inconsistency 2025-08-26 13:58:29 +07:00
end-4 e7ffd2455a sidebars: open by hovering (or clicking) corners 2025-08-26 10:51:40 +07:00
end-4 63b7a3a36c bar: warning for high resource usage 2025-08-26 09:15:59 +07:00
end-4 376f2bfeb1 background: no flash when changing wallpaper 2025-08-26 09:08:01 +07:00
end-4 0a34b139f4 Update Chinese translation; add language toggle options in settings (#1869) 2025-08-26 09:05:51 +07:00
end-4 45d0a8e501 settings: language change notice: use proper rounding value, update chinese translation 2025-08-26 08:56:08 +07:00
end-4 485dd2952e settings: make language selection notice more material 2025-08-26 08:49:46 +07:00
end-4 a111b50e37 remove volume limit in keybind 2025-08-25 21:42:44 +07:00
end-4 b2d14ca101 wallpaper selector: thumbnail generation, fix xdg dir folder icons 2025-08-24 18:59:41 +07:00
end-4 f3ab3573c3 wallpaper selector: style the scrollbar 2025-08-24 16:39:50 +07:00
end-4 ef4ae4480f wallpaper selector: not reinvent MouseArea containsMouse 2025-08-24 16:12:37 +07:00
end-4 8277a2d942 wallpaper selector: fix dark mode 2025-08-24 14:25:39 +07:00
end-4 8bbf040100 wallpaper selector: show folders 2025-08-24 12:20:04 +07:00
月月 e6bb1a3fde translations: add setting language selection and related strings 2025-08-24 04:10:08 +08:00
月月 6df7482b3d translations:update zh_CN.json and en_US.json;
Add "Corner style" and Bar layout to translation
2025-08-24 02:28:33 +08:00
end-4 bdc0ade117 wallpaper selector: quick places 2025-08-23 23:16:18 +07:00
end-4 29a149b340 wallpaper selector: fix some key focus/fallthrough problems 2025-08-23 22:23:28 +07:00
end-4 80af866650 wallpaper selector: directory validation, common file browser keybinds 2025-08-23 22:11:41 +07:00
end-4 1237d9660e hyprland: add laptop lid switch close suspend 2025-08-23 21:56:51 +07:00
end-4 8e6582b801 wallpaper selector: add address bar 2025-08-23 21:06:36 +07:00
end-4 18ad260ce9 wallpaper service: simplify dir setting 2025-08-23 15:59:50 +07:00
end-4 c0933a3b20 wallpaper selector: make it slide from top 2025-08-23 15:59:30 +07:00
end-4 a116ae6ab5 wallpaper selector: nicer layout 2025-08-23 12:25:34 +07:00
end-4 0e2eea7555 wallpaper selector: unfuck grid placement 2025-08-23 10:13:52 +07:00
end-4 767e35851b wallpaper selector: move key handling to root 2025-08-23 09:36:43 +07:00
end-4 a25a3c186b wallpaper selector: add click outside to close 2025-08-22 22:47:21 +07:00
end-4 28256c0a72 wallpaper selector: add shadows 2025-08-22 22:03:41 +07:00
end-4 dac9ed2785 wallpaper selector: add shadows 2025-08-22 22:03:12 +07:00
end-4 9cc576b98d wallpaper selector: move content to a new file 2025-08-22 21:58:13 +07:00
end-4 87c95f7a7f sidebar: ai: add a border around attached image 2025-08-22 21:31:34 +07:00
end-4 4065142830 weather: make the °C not look ass, move "feels like" to popup 2025-08-22 20:54:15 +07:00
end-4 f56308b6e3 use nmtui for network management 2025-08-22 20:31:34 +07:00
end-4 bdbdf7cb83 sidebar: ai: esc to detach file 2025-08-22 20:30:51 +07:00
end-4 9a0f28c003 update.sh: update the warning (#1856) 2025-08-22 19:01:05 +07:00
end-4 2d2d93d5d8 hyprland: add nwg-displays support, make config portable 2025-08-22 18:34:21 +07:00
end-4 8c44dd6119 settings: make edit config button clearer 2025-08-22 18:20:09 +07:00
end-4 0cb1bc4ca5 install.sh: remove no longer true advantage of translations in ags ver 2025-08-22 18:10:12 +07:00
end-4 db83864d78 sidebar: ai: allow pasting image 2025-08-22 16:52:02 +07:00
end-4 63365c2109 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-08-22 16:51:42 +07:00
end-4 9bbc26dd70 settings app: allow volume limit over 100% 2025-08-22 16:51:39 +07:00
end-4 a383cfd125 translations: update Italian language file (#1861) 2025-08-22 10:10:40 +07:00
Salvo Giangreco 8bb9070d9a translations: update Italian language file
Signed-off-by: Salvo Giangreco <giangrecosalvo9@gmail.com>
2025-08-22 02:16:48 +02:00
end-4 690e934a46 ai: gemini: files 2025-08-21 22:53:11 +07:00
end-4 be1974a89e workspace_action.sh: make comments not weird 2025-08-21 09:53:30 +07:00
end-4 d21087b0d9 Feat: Improved Workspace_action.sh and added relative workspace support. (#1850) 2025-08-21 09:48:59 +07:00
end-4 22b1ad087c vertical bar: disable resource circprog anim 2025-08-21 09:26:58 +07:00
end-4 ce25675f73 search: allow hiding actions when the prefix is not that of them
Co-Authored-By: reakjra <85903730+reakjra@users.noreply.github.com>
2025-08-21 09:23:03 +07:00
end-4 955a7696f1 screenshot tool: don't show vertical bar layer hint 2025-08-21 08:25:49 +07:00
end-4 4cfacde337 tray: more flexible overflow menu 2025-08-21 08:25:28 +07:00
end-4 eafa8f02b6 bar: allow inverting tray item list's effect 2025-08-21 07:45:30 +07:00
end-4 1338b65aaa bar: tray overflow menu 2025-08-20 23:05:02 +07:00
end-4 7c8068b2bd background: add vertical parallax 2025-08-20 19:35:33 +07:00
end-4 75f749dbe0 fix screen lock not showing over fullscreen apps for real 2025-08-20 19:14:50 +07:00
ashmartin1810 58910f50e8 minor bug fix
minor bug fix
2025-08-20 16:48:19 +05:30
end-4 36eebffd10 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-08-20 17:47:36 +07:00
end-4 0e8e0e4b06 fix screen lock not showing over fullscreen apps 2025-08-20 17:47:27 +07:00
end-4 8524fb500f readme: make it clear that installation is for illogical-impulse quickshell 2025-08-20 06:47:58 +02:00
end-4 8fd1d9acef vertical bar: fix weird occupied ws highlight when toggling bar floating 2025-08-19 22:16:27 +07:00
end-4 c452dd3538 horizontal bar: fix oversized pills when floating + fix weather hover hitbox 2025-08-19 22:10:45 +07:00
end-4 222f083322 bar: weather: refresh on click 2025-08-19 22:02:07 +07:00
ashmartin1810 47527d7175 Feat: Improved Workspace_action.sh and added relative workspace support.
## Problem
The previous script didnt take into account for relative workspaces, and my previous pull request was... bad.
## Fix
Added smart branching to detect if the target is a literal number(1,2,90), or a relative number(+1, -20) or a string target.
## Bugs
None. ive been stress testing it since the last 2 days,
2025-08-19 20:30:00 +05:30
end-4 6f907f7961 search: add math, shell command, and web search prefixes (#1795) 2025-08-19 21:51:52 +07:00
end-4 891a226fdb notifications: hover prevents timeout 2025-08-19 21:15:59 +07:00
end-4 7cbc707308 bar: show ping icon when ai or booru finished responding 2025-08-19 21:02:17 +07:00
end-4 8d3a036b3b add slidefade text animation to some stuff 2025-08-19 18:09:07 +07:00
end-4 ee21139356 search: remove weird list anim 2025-08-19 18:01:02 +07:00
end-4 b37814e9fa Addresses improper env substitution for terminal launch (#1846) 2025-08-19 07:55:40 +07:00
Souyama 07cca33cb4 Update keybinds.conf
Escape terminal env for keybinds
2025-08-18 22:57:48 +05:30
end-4 980533052b wallpaper selector: remove some useless layout crap 2025-08-18 21:47:55 +07:00
end-4 8124f688da remove manual file:// construction 2025-08-18 21:35:01 +07:00
end-4 89e726b5a2 remove animations that aren't supposed to happen 2025-08-18 21:09:10 +07:00
end-4 42695d9253 Wallpapers: use Process::exec instead of setting command and setting running prop 2025-08-18 21:02:03 +07:00
end-4 28fe7817b4 wallpaper selector: add ipchandler alongside globalshortcut 2025-08-18 21:00:41 +07:00
end-4 6aa37e2529 wallpaper selector: dont cache images 2025-08-18 20:59:26 +07:00
end-4 2d8eb163e7 rename wallpaper overview to wallpaper selector 2025-08-18 20:55:54 +07:00
end-4 445b10d6f0 put wallpaper picker in loader and make it use real thumbnails 2025-08-18 20:41:44 +07:00
end-4 0a4dd832a3 vertical bar: not hide battery icon when full 2025-08-18 19:46:38 +07:00
end-4 8feee4e61a WallpaperOverview: make anims consistent 2025-08-18 18:27:54 +07:00
end-4 fe23017a97 WallpaperOverview: remove unnecessary Variants and Item 2025-08-18 18:25:23 +07:00
end-4 b01b52c8f8 wallpapers: show newer ones first 2025-08-18 18:24:41 +07:00
end-4 0f81d2cace make DockButton not rely on auto-cascaded dockRow.padding 2025-08-18 18:17:14 +07:00
end-4 d051246b7e dock: fix tiny button size 2025-08-18 18:13:49 +07:00
end-4 fd7f22ffba Last fix ru_RU.json (#1842) 2025-08-18 15:50:40 +07:00
relyadev c5c0cf001c Update ru_RU.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-18 08:25:26 +00:00
relyadev ab846062e4 Update ru_RU.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-18 08:25:14 +00:00
relyadev 172e77a6cf Update ru_RU.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-18 08:24:49 +00:00
relyadev 0998d8a0fc Update ru_RU.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-18 08:24:34 +00:00
end-4 71b82730ab config option to allow showing wallpaper when fullscreen 2025-08-18 15:04:04 +07:00
relyadev 6b597bf1fb Update ru_RU.json 2025-08-18 07:34:39 +00:00
end-4 5c431096ec force larger wallpaper picker size 2025-08-18 14:15:33 +07:00
end-4 e278bed251 add floating window rule for shell conflicts killer 2025-08-18 14:11:08 +07:00
end-4 efbcf5469b overview: remove pointless Item 2025-08-18 14:09:40 +07:00
end-4 de0a91619e Make KDE file dialogue always spawn in reasonable size (#1841) 2025-08-18 09:07:07 +02:00
fuggy 7be0c1a034 Make KDE file dialogue always spawn in reasonable size 2025-08-17 16:40:38 -05:00
sin 71e43d6e3d Merge branch 'end-4:main' into main 2025-08-17 17:01:47 +00:00
end-4 a77865379f Added micro text editor keybinds.conf (#1836) 2025-08-17 18:54:19 +02:00
end-4 e20cc9e80f more updates ru_RU.json (#1838) 2025-08-17 18:52:51 +02:00
end-4 c66c920cbe Add Japanese translation (#1839) 2025-08-17 18:52:08 +02:00
rain022 695dbee501 Add Japanese translation 2025-08-18 01:21:50 +09:00
relyadev de44a8d91e more updates ru_RU.json
"Performance Profile toggle": "Переключатель питания"
Didn't fit, changed
Translation became more logical
Almost the entire system is localized
2025-08-17 16:14:29 +00:00
end-4 de6ba1c82e wallpapers: add svg format 2025-08-17 22:54:40 +07:00
end-4 5b1124d658 correct wallpaper path capitalization 2025-08-17 21:50:12 +07:00
relyadev 122b16a720 Added micro text editor keybinds.conf 2025-08-17 14:41:20 +00:00
end-4 dfcf2eec57 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-08-17 21:34:27 +07:00
end-4 9a9a35d75e bar: corrected 💢 popup margins for vertical bar 2025-08-17 21:34:22 +07:00
end-4 ec89c9cdc8 Updated some incorrect words and added new ones to ru_RU.json (#1833) 2025-08-17 16:25:04 +02:00
relyadev e66ab2b2c9 Updated some incorrect words and added new ones to ru_RU.json 2025-08-17 12:16:52 +00:00
end-4 dc167bd25e previous commit but use $qsConfig instead of ii in hyprland config 2025-08-17 18:17:16 +07:00
end-4 680378e68f clipboard history: make updates happen immediately after change
Updates previously wouldn't trigger immediately because no focus = no clipboard grab
https://quickshell.org/docs/v0.2.0/types/Quickshell/Quickshell/#clipboardText
2025-08-17 18:15:01 +07:00
sin 190dbff98d feat(wallpaper selector): add search functionality 2025-08-17 10:51:51 +00:00
end-4 ff7aa46cda background: fix too close date placement for 12h clock 2025-08-17 15:48:33 +07:00
end-4 8c47d85927 background: fix mantra positioning 2025-08-17 15:47:20 +07:00
end-4 de99a3f114 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-08-17 15:40:01 +07:00
end-4 8b77aa151b bars: refractor corner areas' scrolling behavior 2025-08-17 15:39:58 +07:00
end-4 00461468c9 Add `mantra' beneath clock (#1828) 2025-08-17 06:22:20 +02:00
end-4 ad323f7885 remove redundant return 2025-08-17 06:21:23 +02:00
end-4 a50b673e07 disable touchpad scroll tweak by default 2025-08-17 07:31:07 +07:00
Nyx d1e66c4441 It's 9/11, where yo planes at?
Signed-off-by: Nyx <189459385+nyx-4@users.noreply.github.com>
2025-08-16 20:16:38 +05:00
end-4 7cc00b99a1 bar: make right clicking right side not skip current track (closes #1456) 2025-08-16 21:30:12 +07:00
end-4 c745615a2a prompt to kill kded6, mako, dunst (conflicting stuff) 2025-08-16 21:00:56 +07:00
Nyx 7aacac554d [Feature Request] Add `mantra' beneath clock
Signed-off-by: Nyx <189459385+nyx-4@users.noreply.github.com>
2025-08-16 18:25:52 +05:00
end-4 fcab19c392 make bottom/right bar slide anim not go across the screen 2025-08-16 19:20:17 +07:00
end-4 98e2bf53ed add slide rule for vertical bar 2025-08-16 19:19:15 +07:00
end-4 51310e632c fix media controls positioning for vertical bar 2025-08-16 14:47:01 +07:00
end-4 2a46b17958 vertical bar: add date 2025-08-16 11:55:27 +07:00
end-4 e189f0317f move StyledPopup to Bar 2025-08-16 11:54:50 +07:00
end-4 138684fcea vertical bar: add media progress 2025-08-16 08:51:07 +07:00
end-4 23af50a30d vertical bar: hide battery when not available 2025-08-16 08:38:58 +07:00
sinnayuh 28a6284968 feat(wallpaper selector): add wallpaper selector menu 2025-08-15 17:33:10 +01:00
end-4 ce114b33ff fix unresolved import and unsafe undefined access 2025-08-15 22:50:14 +07:00
end-4 d05c451294 bars: refractor bar groups 2025-08-15 22:49:43 +07:00
end-4 9fc0d26eb5 vertical bar 2025-08-15 22:17:27 +07:00
end-4 25a0c88670 bar: workspaces: not have overkill rounding 2025-08-15 22:12:31 +07:00
end-4 0d5d9a04f5 bar: battery indicator: remove useless RowLayout 2025-08-15 22:12:12 +07:00
end-4 f2ed0057bf bar: unify resource usage popups 2025-08-15 22:08:57 +07:00
end-4 661fcfd263 ai: add gpt 5 nano via gh models 2025-08-15 22:07:56 +07:00
end-4 dbed431085 Merge branch 'main' of https://github.com/end-4/dots-hyprland 2025-08-15 17:46:07 +07:00
end-4 fb89ca98f6 BarContent: remove useless Item wrapping left/right sides 2025-08-15 17:46:02 +07:00
end-4 04bec463c7 night light: fix evaluation in midnight (#1815) 2025-08-15 14:27:57 +07:00
Moeta Yuko 25170f0d2c night light: fix evaluation in midnight 2025-08-15 10:18:01 +08:00
end-4 85a522ba14 bar: fix weird tooltip hover target 2025-08-14 21:11:40 +07:00
end-4 a28618ab78 appearance: add barGroupHeight 2025-08-14 19:57:40 +07:00
end-4 955a5ba7f2 bar: not repeat 32 (visual group height) 2025-08-14 15:47:18 +07:00
end-4 dbd23a6ea4 bar: fix weird center group spacing for non-borderless mode 2025-08-14 15:46:19 +07:00
end-4 df93057dd3 readme: fix the size badge color 2025-08-14 15:30:48 +07:00
end-4 3c2b6d4e7f less unsharpening, make bar resource indicators smaller 2025-08-13 17:19:14 +07:00
end-4 2f11e12c75 bar: not show 1px line when autohiding 2025-08-13 09:47:54 +07:00
end-4 2faf615b68 bar: make icon for cpu more readable 2025-08-12 23:54:30 +07:00
end-4 8bb2e0aa97 bar: media: fix progress value 2025-08-12 23:45:45 +07:00
end-4 b6e4a47329 ClippedFilledCircularProgress: not have the padding 2025-08-12 23:43:27 +07:00
end-4 08197fca23 bar: circular progresses: adjust colors, fix them being always at 65% 2025-08-12 23:40:53 +07:00
end-4 423fb90266 bar: make circular progresses of filled style 2025-08-12 23:38:33 +07:00
end-4 67d1d73845 ClippedProgressBar: add unsharpening to highlight 2025-08-12 23:37:09 +07:00
end-4 fa0531b975 background: wallpaper: no caching
https://doc.qt.io/qt-6/qml-qtquick-image.html#cache-prop
2025-08-12 23:36:11 +07:00
end-4 cb01563ba8 bar: make resource numbers have fixed width 2025-08-12 22:09:20 +07:00
end-4 4446259a0b bar: battery: remove unnecessary imports/props 2025-08-12 22:08:44 +07:00
end-4 a5eb2f0ae6 bar: battery: shamshung pill style 2025-08-12 21:40:29 +07:00
end-4 bf4a1097c1 bar: allow any custom icon on topleft corner 2025-08-12 18:26:47 +07:00
end-4 87ebc8761b bar workspaces: fix occupied indication when changing ws group and on init 2025-08-12 18:25:32 +07:00
end-4 4e87ce8f4b bar: battery indicator: use android battery icon 2025-08-12 18:24:53 +07:00
end-4 24d24c1f85 background: add missing raised style 2025-08-12 18:24:27 +07:00
end-4 c88d77e3f8 install script: update final message 2025-08-12 17:52:40 +07:00
end-4 553c42b82c background: comment debug stuff 2025-08-12 16:36:48 +07:00
end-4 3eb1dd3180 background: fix clock going out of the screen vertically 2025-08-12 16:24:45 +07:00
end-4 10b2cf2662 background: fix padding value for least busy region proc 2025-08-12 15:35:56 +07:00
end-4 545fd8b58a background: no more weird clock movement 2025-08-12 15:24:37 +07:00
end-4 2e31972c56 background: fix wrong wallpaper movable space calculation 2025-08-12 14:34:25 +07:00
end-4 d095cb7812 background: fix small wallpapers going off the screen 2025-08-12 11:20:02 +07:00
end-4 fc31d5fd2f fix weird mediacontrols positioning when bar autohides 2025-08-12 10:28:54 +07:00
end-4 d73ba14154 ServicesConfig now edits hyprlock.conf to change the clock format (#1797) 2025-08-12 09:45:09 +07:00
end-4 d8e09e80ff move hyprlock colors file, remove redundant hyprlock matugen template 2025-08-12 09:44:12 +07:00
end-4 211c4fb102 fix weird osd position when bar autohides 2025-08-11 22:46:28 +07:00
end-4 d448b76dd4 fix stuff not getting blurred when transparency is enabled 2025-08-11 22:42:14 +07:00
end-4 e8ebf5af73 bar tooltip: fix placement for autohide 2025-08-11 22:33:11 +07:00
end-4 459dab65ca feat(bar): unified popup handling (follow-up to #1771 and #1773) (#1776) 2025-08-11 22:10:52 +07:00
end-4 73304ef8d4 Merge branch 'main' into all-tooltips 2025-08-11 22:06:56 +07:00
end-4 aa025e4fac bar tooltips: refractor more 2025-08-11 22:05:19 +07:00
end-4 8eac9338fe bar tooltips: add border 2025-08-11 21:18:55 +07:00
end-4 b0deecc0aa bar tooltips: add shadow 2025-08-11 21:18:01 +07:00
end-4 af111a4be9 bar tooltips: format 2025-08-11 21:17:53 +07:00
end-4 6a8a9172b1 bar tooltips: refractor tooltip bg to StyledPopup 2025-08-11 20:33:01 +07:00
end-4 291b997972 bar tooltips: use correct color, add subhead text 2025-08-11 20:12:20 +07:00
end-4 70a5520f47 bar tooltips: adjust icons 2025-08-11 16:33:35 +07:00
end-4 e7397f824b bar tooltips: make em use tooltip color 2025-08-11 16:03:29 +07:00
end-4 0beee14cd8 bar: popups: fix and simplify positioning 2025-08-11 15:52:54 +07:00
end-4 9ba251ff30 Revert "use wl-clip-persist"
This reverts commit 7f1699663d.
2025-08-11 15:31:59 +07:00
end-4 5b24ac037f automatic transparency 2025-08-11 15:09:39 +07:00
end-4 ea70c354ad lock screen: fix incorrect password text 2025-08-11 15:07:47 +07:00
lunstia 1623b456ec Add variable and moved directory to correct one 2025-08-11 02:15:41 -04:00
lunstia 307959ba76 Edit matugen and hyprlock to separate the two 2025-08-11 00:31:22 -04:00
end-4 7f1699663d use wl-clip-persist
so clipboard content won't go away when the content source app is closed
2025-08-10 17:40:23 +07:00
end-4 252675d3ff notifications: smaller icon 2025-08-10 17:24:52 +07:00
end-4 84c45f2068 make scrolling accumulate properly 2025-08-10 16:44:29 +07:00
end-4 5873995e42 settings: add hiding and bottom position options 2025-08-10 16:44:21 +07:00
end-4 077922c667 fix wrong circular progress prop name 2025-08-10 16:15:29 +07:00
end-4 47dcb1523a Added pomodoro timer in sidebarRight, closes #1477 (#1761) 2025-08-10 16:13:03 +07:00
end-4 86f1e63ed2 stopwatch: clear laps on Start 2025-08-10 16:03:37 +07:00
end-4 709415a6b4 rename stuff 2025-08-10 16:02:00 +07:00
Celestial.y fa46485d57 translation: update zh_CN.json (#1762) 2025-08-10 16:51:24 +08:00
end-4 c2d5d2b61a pomodoro: remove unnecessary isLongBreak persistent state 2025-08-10 15:40:42 +07:00
Runze e39c1af5ae chore(bar): add WlrLayer.Overlay in StyledPopup and delete temperature translation 2025-08-10 02:51:54 +08:00
end-4 ca6463cae8 TimerService: not have stupid extra declaration 2025-08-09 22:58:55 +07:00
end-4 0e17b7a981 TimerService: add back emojis, make reset also reset isLongBreak 2025-08-09 22:55:40 +07:00
end-4 bcd1167d39 pomodoro: rename service to TimerService, better stopwatch layout 2025-08-09 22:48:40 +07:00
end-4 fbe17dc3e3 pomodoro: accept event on keybind cuz recommended by qt docs 2025-08-09 22:19:45 +07:00
end-4 b102e5c1a5 pomodoro: remove unnecessary event propagation prevention 2025-08-09 22:15:07 +07:00
end-4 df9a5e398e pomodoro: remove unused notificationTitle var, format 2025-08-09 22:11:06 +07:00
end-4 90fafa219a remove unnecessary qualified access 2025-08-09 22:09:07 +07:00
end-4 9e1b55a749 pomodoro: add cycle indicator, make long break work, fix reset button 2025-08-09 22:06:05 +07:00
end-4 4ca15a1fc3 pomodoro: make pause/resume less weird 2025-08-09 21:36:28 +07:00
end-4 5bf80dae4e pomodoro: move timers to service, specific button logic to widget 2025-08-09 19:45:26 +07:00
end-4 1f4568d22f pomodoro: rename more for consistency 2025-08-09 18:20:14 +07:00
end-4 903a975033 rename getPomodoroSecondsLeft -> pomodoroSecondsLeft 2025-08-09 16:31:03 +07:00
end-4 0ee9afba4f pomodoro: move tabs to their own files, adjust colors 2025-08-09 16:28:17 +07:00
Runze 9b5713d6b4 chore(bar): delete temperature and related reading logic 2025-08-09 14:08:39 +08:00
Runze 94176fad83 feat(bar): unify extraction to StyledPopup and add namespace 2025-08-09 14:02:56 +08:00
end-4 de759b5120 redesign stopwatch 2025-08-09 12:54:53 +07:00
end-4 9bc4ff16a7 make pomodoro timer persistent 2025-08-09 12:54:37 +07:00
end-4 814f6ced5f hide dupe keybind for one thing 2025-08-09 11:08:05 +07:00
end-4 91dae8ad85 pomodoro widget: use grid instead of row/col spam 2025-08-09 10:42:50 +07:00
end-4 fb4f8a86f4 lock screen: use quickshell, add hack for window refocus 2025-08-09 08:56:12 +07:00
end-4 e15d2fe82c easyeffects toggle: move logic to a service 2025-08-09 08:55:29 +07:00
end-4 4ede1c74e8 Run hyprctl directly in HyprlandData service (#1786) 2025-08-09 06:27:37 +07:00
Alvin 9d98396e33 Add missing commas 2025-08-08 14:15:07 -04:00
Alvin e43dcf5d4c run hyprctl directly 2025-08-08 14:11:06 -04:00
end-4 eac4ab3e3c enable faster touchpad scroll 2025-08-08 22:09:45 +07:00
end-4 d256d8fc35 add config option to use "normal" scroll behavior (#1782) 2025-08-08 22:08:50 +07:00
end-4 3157e99e04 keybinds: make super key binds work also with right super 2025-08-08 21:51:30 +07:00
Nyx 91fee0d6e9 Minor tweaks and better variables names
Signed-off-by: Nyx <189459385+nyx-4@users.noreply.github.com>
2025-08-08 19:51:03 +05:00
end-4 521061fc64 sidebar: volume mixer: adjust style 2025-08-08 21:37:32 +07:00
end-4 4328746df0 SecondaryTabButton: make ripple radial gradient 2025-08-08 21:36:45 +07:00
end-4 2b87d939bb make fade of ripple effect longer 2025-08-08 21:03:11 +07:00
end-4 39a88a6cd3 ButtonGroup: add uniformCellSizes 2025-08-08 21:02:45 +07:00
end-4 d0ad416e28 bar: adjust autohide super press show delay 2025-08-08 20:53:47 +07:00
end-4 61e4f59aa0 welcome app: more bar options, extra info on closing 2025-08-08 20:47:20 +07:00
end-4 db66b85e61 bar: move number showing logic from GlobalStates to Workspaces 2025-08-08 20:24:37 +07:00
end-4 66c810ead2 bar autohide: rename enabled -> enable for consistency 2025-08-08 20:12:50 +07:00
end-4 9824bb9c63 bar: add delay for autohide 2025-08-08 20:06:53 +07:00
end-4 f806e2c22c bar: add auto hide 2025-08-08 19:54:10 +07:00
end-4 3d408b18f7 background: add fade when switching 2025-08-08 18:31:52 +07:00
end-4 8aa776ae62 make bg image loading async 2025-08-08 18:02:10 +07:00
end-4 a15f3b8c65 overview: show windows on other monitors too 2025-08-08 17:55:52 +07:00
end-4 4df22c96d0 screen corners: fix visibility for multimonitor with varying fullscreen state 2025-08-08 17:52:19 +07:00
end-4 772df06fa5 booru: fix inconsistent download 2025-08-08 17:50:20 +07:00
Saint2999 e1b7336d5d Hide online model on local ai policy 2025-08-08 07:46:02 +03:00
end-4 d3a9d2ea5b Fix hiding background when fullscreen (#1775) 2025-08-08 10:35:55 +07:00
end-4 4914d9b638 Merge branch 'main' into main 2025-08-08 10:35:43 +07:00
end-4 1f8a7be34e quickshell: fix qml null safety and monitor property errors (#1770) 2025-08-08 00:01:31 +07:00
end-4 97bdfa54c0 Overrideable default terminal app (#1753) 2025-08-07 23:57:08 +07:00
end-4 64bb730dd1 touchpad: improve scroll speed handling for touchpad (#1781) 2025-08-07 23:46:39 +07:00
end-4 7013b459a3 adjust scrolling speed 2025-08-07 23:13:07 +07:00
end-4 a31733e2db move scrolling animation to styled components 2025-08-07 22:39:30 +07:00
end-4 199b23d14a add config options for scroll factors and threshold 2025-08-07 22:32:02 +07:00
end-4 f1c1ed833c use StyledListView for SelectionDialog 2025-08-07 22:31:19 +07:00
Souyama 0506917b87 launch_first_available.sh should skip empty cmds 2025-08-07 20:48:11 +05:30
end-4 4f40ba8e6e more intuitive power profiles icons 2025-08-07 22:01:05 +07:00
end-4 733a792610 ai: add usage metadata for openai and mistral 2025-08-07 21:53:37 +07:00
end-4 f581fd4821 config option to (not) filter duplicate media controls 2025-08-07 21:39:48 +07:00
Runze 86ddb61a3f fix(touchpad): differentiate scroll speed between touchpad and mouse wheel 2025-08-07 22:26:26 +08:00
lunstia 6c3451b912 Fix background not always hiding in fullscreen and other monitors hiding background when they're not supposed to 2025-08-07 00:16:26 -04:00
Runze 627c8562f7 fix(bar): prevent hover popup from appearing for hidden resource icons 2025-08-06 19:28:37 +08:00
Runze 061bb2abeb feat(bar): unify popup handling and improve layouts
- Unified popup handling in ClockWidget, Resource, BatteryPopup, and WeatherBar
  using PanelWindow + LazyLoader for consistent positioning and compositor animations.
- Replaced plain text with ColumnLayout and RowLayout where possible, adding
  MaterialSymbol icons for improved visual consistency with the overall desktop style.
- Added Translation.tr() for bilingual (Chinese/English) support to avoid hardcoded strings.
- Based on improvements from PR #1771 (mine) and PR #1773 (by @finjener), merged and refined into a more polished and practical solution.
2025-08-06 18:02:55 +08:00
lunstia 35e1dc95a5 Fix background hiding in fullscreen 2025-08-06 05:27:29 -04:00
finjener 1dc46fa104 feat(bar): add hover popups for system resources and upcoming todos
- Add detailed popups for memory, swap, and CPU resource icons
- Add todo integration popup for date/time widget
2025-08-06 15:30:49 +08:00
Runze 4161467356 use PanelWindow instead to show animation 2025-08-06 01:31:02 +08:00
finjener d70f81bfe4 Merge remote-tracking branch 'upstream/main' into quickshell-fixes 2025-08-05 18:17:02 +01:00
Nyx bfb7ccffb5 Reworked on Pomodoro's UI and added Stopwatch
Signed-off-by: Nyx <189459385+nyx-4@users.noreply.github.com>
2025-08-05 16:06:22 +05:00
Runze 3a6c032782 Added a small battery popup to show information 2025-08-05 17:21:36 +08:00
finjener d632111cf9 quickshell: fix qml null safety and monitor property errors 2025-08-04 23:03:00 +01:00
Nyx e4b761917a Polished the UI and added Persistent Config option.
Signed-off-by: Nyx <189459385+nyx-4@users.noreply.github.com>

Changelog:
Added Config.options.time.pomodoro options in Config.qml
Restructered the Pomodoro logic and added Long break
Used timestamp instead of naively counting down.
Major UI tweaks.
2025-08-03 20:36:29 +05:00
end-4 f8d162d995 RoundCorner: rewrite to use Shape instead of Canvas 2025-08-03 20:40:52 +07:00
end-4 0708070764 circular progress: use implicitSize instead of size
note: the credit is removed because the widget has been rewritten to use Shape instead of Canvas
2025-08-03 19:54:01 +07:00
end-4 87f7bc28a3 chores: remove unnecessary import, suppress init null warnings 2025-08-03 18:17:01 +07:00
end-4 3eb7d8ab58 background: remove unecessary Scope 2025-08-03 18:13:12 +07:00
end-4 71d0ac4c5e make circular progresses use shape instead of canvas 2025-08-03 18:12:44 +07:00
end-4 839593b11e add konsole konfig 2025-08-03 17:31:58 +07:00
end-4 13a0927900 bar: refractor bar content to new file 2025-08-03 16:52:39 +07:00
end-4 00984c599b settings: update keep right sidebar loaded note 2025-08-03 16:51:08 +07:00
end-4 34ca65a180 background: fix wrong anchor 2025-08-03 16:11:24 +07:00
月月 9df7129c6c translation: update zh_CN.json 2025-08-03 09:42:43 +08:00
Nyx 0b9717c2a5 Added pomodoro timer in sidebarRight, closes #1477
Signed-off-by: Nyx <189459385+nyx-4@users.noreply.github.com>
2025-08-02 22:17:56 +05:00
end-4 596ae72942 add config option to keep right sidebar loaded 2025-08-02 20:31:37 +07:00
end-4 88cc91b85a fix laggy search bar anim when overview is disabled 2025-08-02 20:09:18 +07:00
end-4 d4b8ded6c8 overview: allow disabling overview (showing search only) 2025-08-02 17:35:44 +07:00
end-4 86d2a03a0a settings: add monochromize/tint icons toggles 2025-08-02 16:56:19 +07:00
end-4 de1812bf91 sidebar: remove redundant coloroverlay, make uptime more brief 2025-08-02 16:55:56 +07:00
end-4 f36751ff6b sidebar: boorus: always download images manually 2025-08-02 16:01:46 +07:00
end-4 a9273fc225 ai: dont include tool instructions in system prompt 2025-08-02 16:00:24 +07:00
end-4 2a0b12112f i use nyarch btw 2025-08-02 15:45:24 +07:00
end-4 2aea02989f session: fix binding breakage on close (#1754) 2025-08-02 07:25:08 +07:00
Souyama 2b554cf286 Update env.conf
remote direct quotes
2025-08-02 00:28:47 +05:30
sansmoraxz dc2777703d update default terminal value 2025-08-01 22:47:01 +05:30
sansmoraxz 6ae03b545c terminal env var 2025-08-01 22:22:01 +05:30
end-4 8e366cfc84 translations: add ukrainian language file (#1748) 2025-08-01 22:56:27 +07:00
Beengoo 27c2c4fb92 Merge branch 'end-4:main' into main 2025-08-01 15:53:42 +03:00
Beengoo 83af589b27 Correcting localization errors 2025-08-01 15:44:47 +03:00
end-4 7a937833f3 background: parallax on whole workspace group 2025-08-01 08:16:19 +07:00
end-4 4110d2529c ai: dont replace . in ollama model name 2025-07-31 22:28:34 +07:00
Beengoo 1c6c165d78 Added Ukrainian Language 2025-07-31 17:17:48 +03:00
end-4 a5ffb0e021 media controls: actually detect if plasma browser integration is installed 2025-07-31 12:35:39 +07:00
end-4 a08a39b620 qs: handle toggles internally instead of relying on hyprctl dispatch global (#1745) 2025-07-31 12:35:16 +07:00
end-4 968e8195ef background: fix clock positioning 2025-07-30 12:33:55 +07:00
end-4 52ce2f5384 feat(background): show clock for video wallpapers. (#1719) 2025-07-30 07:30:15 +02:00
end-4 cb2d1bc444 Merge branch 'main' into videowall-add-clock 2025-07-30 07:30:05 +02:00
end-4 47b81faf3d Feature: Hyprlock layout indicator (#1718) 2025-07-30 07:15:33 +02:00
end-4 1483761e72 Feature: On-screen keyboard (osk) update on activeLayout event (#1717) 2025-07-30 07:11:05 +02:00
end-4 7f43665e3c Merge branch 'main' into osk-update-on-activelayout-event 2025-07-30 07:10:48 +02:00
end-4 01fcd653ad Fix: Init layout indicator with main keyboard and update on every activeLayout event (#1711) (#1716) 2025-07-30 06:57:40 +02:00
end-4 298e947740 background: hide when fullscreen 2025-07-30 09:46:55 +07:00
end-4 91c2014b7e ai: add mistral 2025-07-30 09:46:42 +07:00
end-4 3018ad16b1 translation: Update Russian translation file (again) (#1741) 2025-07-30 00:44:34 +02:00
Anton Epikhin 1172be241c Returned fade_on_empty for input field and moved layout indicator to bottom right 2025-07-29 22:02:25 +03:00
Vercixx c743b4ab88 Update ru_RU.json 2025-07-29 21:45:56 +03:00
end-4 f6ec718ced translation: Update Russian translation file (#1740) 2025-07-29 16:43:04 +02:00
Vercixx aa20027de4 translation: Update Russian translation file 2025-07-29 16:27:30 +03:00
end-4 e504cf11e1 starship: fix trailing newline (#1738) 2025-07-29 19:01:09 +07:00
end-4 a11e0a39d9 ai: adjust chat input indicator spacing 2025-07-29 16:42:18 +07:00
end-4 26531401b0 ai: allow custom models 2025-07-29 16:38:21 +07:00
end-4 0f4293e4cb background: clock "separate" from bg image 2025-07-28 22:49:01 +07:00
end-4 7172b134ea ai: more context in system prompt 2025-07-28 22:40:54 +07:00
end-4 4a9e342a1c ai: add suggestions for /tool 2025-07-28 18:11:23 +07:00
end-4 f98d869c21 why 2025-07-28 10:38:16 +02:00
end-4 1312310a6e translation: update vietnamese 2025-07-28 13:33:49 +07:00
end-4 ad9c81f405 translation: Add Russian translation (#1732) 2025-07-28 08:16:51 +02:00
end-4 496caa6fb1 fix weirdass scroll speed 2025-07-28 11:58:50 +07:00
end-4 2fd7d45b9c deps: add hyprsunset 2025-07-28 07:31:11 +07:00
Vercixx 0b087665a8 translation: Add Russian translation 2025-07-27 22:33:49 +03:00
end-4 39862fba2a make panel borders more subtle 2025-07-27 22:44:08 +07:00
end-4 3ac44d211f ai: separate model and tool selection 2025-07-27 22:33:25 +07:00
end-4 d3392000af translations: add Italian language file (#1723) 2025-07-27 15:48:44 +02:00
Salvo Giangreco 564d2e109f translations: add Italian language file
Signed-off-by: Salvo Giangreco <giangrecosalvo9@gmail.com>
2025-07-27 14:52:59 +02:00
end-4 fe07298adb hyprlanddata: use stdiocollector instead of jq hack with splitparser 2025-07-27 08:51:43 +07:00
end-4 cc176a999d Fix empty notifications (#1728) 2025-07-27 03:12:19 +02:00
Javier Rolando 47c5a41aa6 fix empty notifications 2025-07-26 20:49:04 -03:00
end-4 2ad6f2c9fc Make Performance profile setting translatable (#1725) 2025-07-27 00:54:10 +02:00
Vercixx 8905bc1c27 Make Performance toggle translatable 2025-07-26 16:58:43 +03:00
end-4 064d5174c2 ai: add command execution requests 2025-07-26 14:20:55 +07:00
end-4 c69c8f6ef5 osd: make spinning brightness icon not wiggle 2025-07-26 14:12:43 +07:00
end-4 7fb81049f3 welcome app: fix material theme 2025-07-26 09:09:52 +07:00
end-4 5099ce15db session: detect running downloads 2025-07-25 23:09:17 +07:00
lyingfish ed500395d3 feat(background): show clock for video wallpapers.\ 2025-07-25 21:38:47 +08:00
Anton Epikhin a1e88fc3c2 Added hyprlock layout indicator 2025-07-25 16:35:42 +03:00
end-4 c8b007631d ai: refractor api formats 2025-07-25 20:14:37 +07:00
Anton Epikhin 6bc1f8a39f OSK update on activeLayout event 2025-07-25 14:26:49 +03:00
Anton Epikhin fe84f6cab1 init indicator with main keyboard and update layout on every activelayout event 2025-07-25 11:33:16 +03:00
end-4 27eea1c7a6 feat: power-profile switcher in topbar (#1653) 2025-07-25 09:11:46 +02:00
end-4 32f94704c7 bar: power profiles: change icon for "balanced" 2025-07-25 14:10:55 +07:00
end-4 05fdbf3d24 rename showPerfProfileToggle -> showPerformanceProfileToggle 2025-07-25 13:58:40 +07:00
end-4 f28c791cf2 hyprlock: remove misleading comments in default config 2025-07-25 10:40:53 +07:00
end-4 a4b474ff39 wallpaper: more flexible parallax 2025-07-25 10:39:58 +07:00
end-4 38c76fe86b Fix: Always scroll clipboard history to top when content changes (#1690) (#1713) 2025-07-25 04:31:46 +02:00
end-4 d09259c79a search: fix clipboard gets scrolled to bottom 2025-07-25 09:30:59 +07:00
Celestial.y a683fa2414 feat: add option to ignore conflicting files (#1613) 2025-07-25 08:58:39 +08:00
MrRogueKnight e744816928 Update SearchWidget.qml 2025-07-25 01:53:31 +05:30
end-4 15703bce04 session: detect more package managers 2025-07-24 21:40:35 +07:00
end-4 f4f5540d08 qs: use new qs import for search algorithms 2025-07-24 20:45:57 +07:00
end-4 b1b37685c1 session: warn when package manager is running 2025-07-24 20:41:44 +07:00
end-4 0ff4cc572c sidebar: ai: clearer statusbar tooltips 2025-07-24 19:37:27 +07:00
end-4 081b9c17d5 tooltip colors follow m3 docs again 2025-07-24 19:36:50 +07:00
end-4 eb6b21e7e6 ai: add api key indicator 2025-07-24 19:28:45 +07:00
end-4 baa17c304b ai: show search queries, temperature, and token count 2025-07-24 18:05:21 +07:00
end-4 7b8b388667 ai: make temperature actually work 2025-07-24 16:24:27 +07:00
end-4 118529d8d3 ai: gemini 2.5: update model codes, add flash lite 2025-07-24 16:19:26 +07:00
end-4 b67c4553f6 bar: layout indicator: make not freaking tiny 2025-07-23 22:25:18 +07:00
end-4 47980da78e Layout indicator for Hyprland kb_layout option (#1471) 2025-07-23 17:22:04 +02:00
end-4 3d57d444df Merge branch 'main' into layout_service 2025-07-23 17:20:38 +02:00
end-4 5870632c19 Merge remote-tracking branch 'upstream/main' into layout_service 2025-07-23 22:18:22 +07:00
end-4 ffeb27f04e bar: layout indicator: smaller 2025-07-23 22:12:54 +07:00
end-4 012df9dcd7 hyprlandxkb: dont update when not necessary 2025-07-23 22:11:40 +07:00
end-4 82fd2334cf bar: layout indicator: more proper layout parsing 2025-07-23 22:07:34 +07:00
end-4 7bafa57989 radiobutton: fix inaccurate height 2025-07-23 10:26:16 +07:00
end-4 5b4ccd9d59 previous commit but i didn't know there are 2 spots to fix 2025-07-23 09:34:23 +07:00
end-4 be2b86909a switchwall: fix mpv options being overriden by load-scripts only (#1696) 2025-07-23 09:26:52 +07:00
end-4 82506ae7cd groupbutton: press and hold for alt action 2025-07-23 09:00:54 +07:00
end-4 574a2a11e7 night light: use hyprsunset <- gammastep 2025-07-23 09:00:31 +07:00
end-4 3d5ed9401c bar: don't animate circprogs (#1570) 2025-07-23 08:57:33 +07:00
end-4 3b5a674409 fix(ai): add the full received message to rawContent (OpenAi format) (#1695) 2025-07-22 15:22:42 +02:00
Jonas Bloch f9856bdabd fix(ai): add the full received message to rawContent
The messages were not preserved and passed to further calls outside of the reasoning part.
2025-07-22 09:50:51 +02:00
end-4 b6f75acf53 quickshell: configPath -> shellPath 2025-07-22 09:17:17 +07:00
end-4 c0f7504b36 bar: tray: not make icons fully monochrome 2025-07-22 09:17:03 +07:00
Ninjdai 365a649776 Update UtilButtons.qml 2025-07-16 10:31:49 +02:00
Ninjdai 0ecf72b4c3 Merge branch 'end-4:main' into power-profile-toggle 2025-07-16 10:28:48 +02:00
Ninjdai 90013c7451 feat: power-profile switcher in topbar 2025-07-15 22:44:24 +02:00
obsidrielle 715aa8d845 feat: add option to ignore conflicting files 2025-07-11 13:37:25 +08:00
スケベ ad7fdd1d3f layout indicator in top right 2025-06-19 18:14:05 +03:00
828 changed files with 41056 additions and 14923 deletions
-29
View File
@@ -1,29 +0,0 @@
function fish_prompt -d "Write out the prompt"
# This shows up as USER@HOST /home/user/ >, with the directory colored
# $USER and $hostname are set by fish, so you can just use them
# instead of using `whoami` and `hostname`
printf '%s@%s %s%s%s > ' $USER $hostname \
(set_color $fish_color_cwd) (prompt_pwd) (set_color normal)
end
if status is-interactive
# Commands to run in interactive sessions can go here
set fish_greeting
end
starship init fish | source
if test -f ~/.local/state/quickshell/user/generated/terminal/sequences.txt
cat ~/.local/state/quickshell/user/generated/terminal/sequences.txt
end
alias pamcan pacman
alias ls 'eza --icons'
alias clear "printf '\033[2J\033[3J\033[1;1H'"
alias q 'qs -c ii'
# function fish_prompt
# set_color cyan; echo (pwd)
# set_color green; echo '> '
# end
-21
View File
@@ -1,21 +0,0 @@
# This file sources other files in `hyprland` and `custom` folders
# You wanna add your stuff in files in `custom`
$qsConfig = ii
exec = hyprctl dispatch submap global # DO NOT REMOVE THIS OR YOU WON'T BE ABLE TO USE ANY KEYBIND
submap = global # This is required for catchall to work
# Defaults
source=~/.config/hypr/hyprland/env.conf
source=~/.config/hypr/hyprland/execs.conf
source=~/.config/hypr/hyprland/general.conf
source=~/.config/hypr/hyprland/rules.conf
source=~/.config/hypr/hyprland/colors.conf
source=~/.config/hypr/hyprland/keybinds.conf
# Custom
source=~/.config/hypr/custom/env.conf
source=~/.config/hypr/custom/execs.conf
source=~/.config/hypr/custom/general.conf
source=~/.config/hypr/custom/rules.conf
source=~/.config/hypr/custom/keybinds.conf
-42
View File
@@ -1,42 +0,0 @@
#!/usr/bin/env bash
getdate() {
date '+%Y-%m-%d_%H.%M.%S'
}
getaudiooutput() {
pactl list sources | grep 'Name' | grep 'monitor' | cut -d ' ' -f2
}
getactivemonitor() {
hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .name'
}
xdgvideo="$(xdg-user-dir VIDEOS)"
if [[ $xdgvideo = "$HOME" ]]; then
unset xdgvideo
fi
mkdir -p "${xdgvideo:-$HOME/Videos}"
cd "${xdgvideo:-$HOME/Videos}" || exit
if pgrep wf-recorder > /dev/null; then
notify-send "Recording Stopped" "Stopped" -a 'Recorder' &
pkill wf-recorder &
else
if [[ "$1" == "--fullscreen-sound" ]]; then
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown
wf-recorder -o "$(getactivemonitor)" --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio="$(getaudiooutput)"
elif [[ "$1" == "--fullscreen" ]]; then
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown
wf-recorder -o "$(getactivemonitor)" --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t
else
if ! region="$(slurp 2>&1)"; then
notify-send "Recording cancelled" "Selection was cancelled" -a 'Recorder' & disown
exit 1
fi
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown
if [[ "$1" == "--sound" ]]; then
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" --audio="$(getaudiooutput)"
else
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region"
fi
fi
fi
@@ -1,2 +0,0 @@
#!/usr/bin/env bash
hyprctl dispatch "$1" $(((($(hyprctl activeworkspace -j | jq -r .id) - 1) / 10) * 10 + $2))
@@ -1,24 +0,0 @@
// vim: set ft=glsl:
precision highp float;
varying highp vec2 v_texcoord;
uniform highp sampler2D tex;
#define STRENGTH 0.0027
void main() {
vec2 center = vec2(0.5, 0.5);
vec2 offset = (v_texcoord - center) * STRENGTH;
float rSquared = dot(offset, offset);
float distortion = 1.0 + 1.0 * rSquared;
vec2 distortedOffset = offset * distortion;
vec2 redOffset = vec2(distortedOffset.x, distortedOffset.y);
vec2 blueOffset = vec2(distortedOffset.x, distortedOffset.y);
vec4 redColor = texture2D(tex, v_texcoord + redOffset);
vec4 blueColor = texture2D(tex, v_texcoord + blueOffset);
gl_FragColor = vec4(redColor.r, texture2D(tex, v_texcoord).g, blueColor.b, 1.0);
}
-511
View File
@@ -1,511 +0,0 @@
#version 100
precision highp float;
varying highp vec2 v_texcoord;
varying highp vec3 v_pos;
uniform highp sampler2D tex;
uniform lowp float time;
#define BORDER_COLOR vec4(vec3(0.0, 0.0, 0.0), 1.0) // black border
#define BORDER_RADIUS 1.0 // larger vignette radius
#define BORDER_SIZE 0.01 // small border size
#define CHROMATIC_ABERRATION_STRENGTH 0.00
#define DENOISE_INTENSITY 0.0001 //
#define DISTORTION_AMOUNT 0.00 // moderate distortion amount
#define HDR_BLOOM 0.75 // bloom intensity
#define HDR_BRIGHTNESS 0.011 // brightness
#define HDR_CONTRAST 0.011 // contrast
#define HDR_SATURATION 1.0// saturation
#define LENS_DISTORTION_AMOUNT 0.0
#define NOISE_THRESHOLD 0.0001
#define PHOSPHOR_BLUR_AMOUNT 0.77 // Amount of blur for phosphor glow
#define PHOSPHOR_GLOW_AMOUNT 0.77 // Amount of phosphor glow
#define SAMPLING_RADIUS 0.0001
#define SCANLINE_FREQUENCY 540.0
#define SCANLINE_THICKNESS 0.0507
#define SCANLINE_TIME time * 471.24
#define SHARPNESS 0.25
#define SUPERSAMPLING_SAMPLES 16.0
#define VIGNETTE_RADIUS 0.0 // larger vignette radius
#define PI 3.14159265359
#define TWOPI 6.28318530718
vec2 applyBarrelDistortion(vec2 coord, float amt) {
vec2 p = coord.xy / vec2(1.0);
vec2 v = p * 2.0 - vec2(1.0);
float r = dot(v, v);
float k = 1.0 + pow(r, 2.0) * pow(amt, 2.0);
vec2 result = v * k;
return vec2(0.5, 0.5) + 0.5 * result.xy;
}
vec4 applyColorCorrection(vec4 color) {
color.rgb *= vec3(1.0, 0.79, 0.89);
return vec4(color.rgb, 1.0);
}
vec4 applyBorder(vec2 tc, vec4 color, float borderSize, vec4 borderColor) {
float dist_x = min(tc.x, 1.0 - tc.x);
float dist_y = min(tc.y, 1.0 - tc.y);
float dist = min(dist_x, dist_y) * -1.0;
float border = smoothstep(borderSize, 0.0, dist);
border += smoothstep(borderSize, 0.0, dist);
return mix(color, borderColor, border);
}
vec4 applyFakeHDR(vec4 color, float brightness, float contrast, float saturation, float bloom) {
color.rgb = (color.rgb - vec3(0.5)) * exp2(brightness) + vec3(0.5);
vec3 crtfactor = vec3(1.05, 0.92, 1.0);
color.rgb = pow(color.rgb, crtfactor);
// // NTSC
// vec3 lumCoeff = vec3(0.2125, 0.7154, 0.0721);
// // BT.709
// vec3 lumCoeff = vec3(0.299, 0.587, 0.114);
// BT.2020
vec3 lumCoeff = vec3(0.2627, 0.6780, 0.0593);
// // Warm NTSC
// vec3 lumCoeff = vec3(0.2125, 0.7010, 0.0865);
float luminance = dot(color.rgb, lumCoeff);
luminance = pow(luminance, 2.2);
color.rgb = mix(vec3(luminance), color.rgb, saturation);
color.rgb = mix(color.rgb, vec3(1.0), pow(max(0.0, luminance - 1.0 + bloom), 4.0));
return color;
}
vec4 applyVignette(vec4 color) {
vec2 center = vec2(0.5, 0.5); // center of screen
float radius = VIGNETTE_RADIUS; // radius of vignette effect
float softness = 1.0; // softness of vignette effect
float intensity = 0.7; // intensity of vignette effect
vec2 offset = v_texcoord - center; // offset from center of screen
float distance = length(offset); // distance from center of screen
float alpha = smoothstep(radius, radius - radius * softness, distance) * intensity; // calculate alpha value for vignette effect
return mix(vec4(0.0, 0.0, 0.0, alpha), color, alpha); // mix black with color using calculated alpha value
}
vec4 applyPhosphorGlow(vec2 tc, vec4 color, sampler2D tex) {
// Calculate average color value of the texture
vec4 texelColor = color;
float averageColor = (texelColor.r + texelColor.g + texelColor.b) / 3.0;
// Determine brightness-dependent color factor
float factor = mix(
mix(0.09,
mix(0.005, 0.0075, (averageColor - 0.1) / 0.1),
step(0.01, averageColor)), 0.0005,
step(0.02, averageColor));
// Apply phosphor glow effect
vec4 sum = vec4(0.0);
vec4 pixels[9];
pixels[0] = texture2D(tex, tc - vec2(0.001, 0.001));
pixels[1] = texture2D(tex, tc - vec2(0.001, 0.0));
pixels[2] = texture2D(tex, tc - vec2(0.001, -0.001));
pixels[3] = texture2D(tex, tc - vec2(0.0, 0.001));
pixels[4] = texture2D(tex, tc);
pixels[5] = texture2D(tex, tc + vec2(0.001, 0.001));
pixels[6] = texture2D(tex, tc + vec2(0.001, 0.0));
pixels[7] = texture2D(tex, tc + vec2(0.001, -0.001));
pixels[8] = texture2D(tex, tc + vec2(0.0, 0.001));
// Perform operations on input pixels in parallel
sum = pixels[0]
+ pixels[1]
+ pixels[2]
+ pixels[3]
+ pixels[4]
+ pixels[5]
+ pixels[6]
+ pixels[7]
+ pixels[8];
sum /= 9.0;
sum += texture2D(tex, tc - vec2(0.01, 0.01)) * 0.001;
sum += texture2D(tex, tc - vec2(0.0, 0.01)) * 0.001;
sum += texture2D(tex, tc - vec2(-0.01, 0.01)) * 0.001;
sum += texture2D(tex, tc - vec2(0.01, 0.0)) * 0.001;
sum += color * PHOSPHOR_BLUR_AMOUNT;
sum += texture2D(tex, tc - vec2(-0.01, 0.0)) * 0.001;
sum += texture2D(tex, tc - vec2(0.01, -0.01)) * 0.001;
sum += texture2D(tex, tc - vec2(0.0, -0.01)) * 0.001;
sum += texture2D(tex, tc - vec2(-0.01, -0.01)) * 0.001;
sum *= PHOSPHOR_GLOW_AMOUNT;
// Initialize sum_sum_factor to zero
vec4 sum_sum_factor = vec4(0.0);
// Compute sum_j for i = -1
vec4 sum_j = vec4(0.0);
sum_j += texture2D(tex, tc + vec2(-1, -1) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, -1) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, -1) * 0.01);
sum_j += texture2D(tex, tc + vec2(-1, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(-1, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, 1) * 0.01);
sum_sum_factor += sum_j * vec4(0.011);
// Compute sum_j for i = 0
sum_j = vec4(0.0);
sum_j += texture2D(tex, tc + vec2(-1, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(-1, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, 1) * 0.01);
sum_sum_factor += sum_j * vec4(0.011);
// Compute sum_j for i = 1
sum_j = vec4(0.0);
sum_j += texture2D(tex, tc + vec2(-1, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, 0) * 0.01);
sum_j += texture2D(tex, tc + vec2(-1, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(0, 1) * 0.01);
sum_j += texture2D(tex, tc + vec2(1, 1) * 0.01);
sum_sum_factor += sum_j * vec4(0.011);
color += mix(sum_sum_factor * sum_sum_factor * vec4(factor), sum, 0.5);
return color;
}
vec4 applyAdaptiveSharpen(vec2 tc, vec4 color, sampler2D tex) {
vec4 color_tl = texture2D(tex, tc + vec2(-1.0, -1.0) * 0.5 / 2160.0);
vec4 color_tr = texture2D(tex, tc + vec2(1.0, -1.0) * 0.5 / 2160.0);
vec4 color_bl = texture2D(tex, tc + vec2(-1.0, 1.0) * 0.5 / 2160.0);
vec4 color_br = texture2D(tex, tc + vec2(1.0, 1.0) * 0.5 / 2160.0);
float sharpness = SHARPNESS;
vec3 color_no_alpha = color.rgb;
vec3 color_tl_no_alpha = color_tl.rgb;
vec3 color_tr_no_alpha = color_tr.rgb;
vec3 color_bl_no_alpha = color_bl.rgb;
vec3 color_br_no_alpha = color_br.rgb;
float delta = (dot(color_no_alpha, vec3(0.333333)) + dot(color_tl_no_alpha, vec3(0.333333)) + dot(color_tr_no_alpha, vec3(0.333333)) + dot(color_bl_no_alpha, vec3(0.333333)) + dot(color_br_no_alpha, vec3(0.333333))) * 0.2 - dot(color_no_alpha, vec3(0.333333));
vec3 sharp_color_no_alpha = color_no_alpha + min(vec3(0.0), vec3(delta * sharpness));
vec4 sharp_color = vec4(sharp_color_no_alpha, color.a);
return sharp_color;
}
vec4 applyScanlines(vec2 tc, vec4 color) {
float scanline = (cos(tc.y * SCANLINE_FREQUENCY + SCANLINE_TIME) *
sin(tc.y * SCANLINE_FREQUENCY + SCANLINE_TIME)) * SCANLINE_THICKNESS;
float alpha = clamp(1.0 - abs(scanline), 0.0, 1.0);
return vec4(color.rgb * alpha, color.a);
}
vec4 applyChromaticAberration(vec2 uv, vec4 color) {
vec2 center = vec2(0.5, 0.5); // center of the screen
vec2 offset = (uv - center) * CHROMATIC_ABERRATION_STRENGTH; // calculate the offset from the center
// apply lens distortion
float rSquared = dot(offset, offset);
float distortion = 1.0 + LENS_DISTORTION_AMOUNT * rSquared;
vec2 distortedOffset = offset * distortion;
// apply chromatic aberration
vec2 redOffset = vec2(distortedOffset.x * 1.00, distortedOffset.y * 1.00);
vec2 blueOffset = vec2(distortedOffset.x * 1.00, distortedOffset.y * 1.00);
vec4 redColor = texture2D(tex, uv + redOffset);
vec4 blueColor = texture2D(tex, uv + blueOffset);
vec4 result = vec4(redColor.r, color.g, blueColor.b, color.a);
return result;
}
vec4 reduceGlare(vec4 color) {
// Calculate the intensity of the color by taking the average of the RGB components
float intensity = (color.r + color.g + color.b) / 3.0;
// Set the maximum intensity that can be considered for glare
float maxIntensity = 0.98;
// Use smoothstep to create a smooth transition from no glare to full glare
// based on the intensity of the color and the maximum intensity
float glareIntensity = smoothstep(maxIntensity - 0.02, maxIntensity, intensity);
// Set the amount of glare to apply to the color
float glareAmount = 0.02;
// Mix the original color with the reduced color that has glare applied to it
vec3 reducedColor = mix(color.rgb, vec3(glareIntensity), glareAmount);
// Return the reduced color with the original alpha value
return vec4(reducedColor, color.a);
}
// Apply a fake HDR effect to the input color.
// Parameters:
// - inputColor: the color to apply the effect to.
// - brightness: the brightness of the image. Should be a value between 0 and 1.
// - contrast: the contrast of the image. Should be a value between 0 and 1.
// - saturation: the saturation of the image. Should be a value between 0 and 2.
// - bloom: the intensity of the bloom effect. Should be a value between 0 and 1.
vec4 applyFakeHDREffect(vec4 inputColor, float brightness, float contrast, float saturation, float bloom) {
const float minBrightness = 0.0;
const float maxBrightness = 1.0;
const float minContrast = 0.0;
const float maxContrast = 1.0;
const float minSaturation = 0.0;
const float maxSaturation = 2.0;
const float minBloom = 0.0;
const float maxBloom = 1.0;
// Check input parameters for validity
if (brightness < minBrightness || brightness > maxBrightness) {
return vec4(0.0, 0.0, 0.0, 1.0); // Return black with alpha of 1.0 to indicate error
}
if (contrast < minContrast || contrast > maxContrast) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
if (saturation < minSaturation || saturation > maxSaturation) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
if (bloom < minBloom || bloom > maxBloom) {
return vec4(0.0, 0.0, 0.0, 1.0);
}
// Apply brightness and contrast
vec3 color = inputColor.rgb;
color = (color - vec3(0.5)) * exp2(brightness * 10.0) + vec3(0.5);
color = mix(vec3(0.5), color, pow(contrast * 4.0 + 1.0, 2.0));
// // NTSC
// vec3 lumCoeff = vec3(0.2125, 0.7154, 0.0721);
// // BT.709
// vec3 lumCoeff = vec3(0.299, 0.587, 0.114);
// // BT.2020
// vec3 lumCoeff = vec3(0.2627, 0.6780, 0.0593);
// Warm NTSC
vec3 lumCoeff = vec3(0.2125, 0.7010, 0.0865);
// Apply saturation
float luminance = dot(color, lumCoeff);
vec3 grey = vec3(luminance);
color = mix(grey, color, saturation);
// Apply bloom effect
float threshold = 1.0 - bloom;
vec3 bloomColor = max(color - threshold, vec3(0.0));
bloomColor = pow(bloomColor, vec3(2.0));
bloomColor = mix(vec3(0.0), bloomColor, pow(min(luminance, threshold), 4.0));
color += bloomColor;
return vec4(color, inputColor.a);
}
vec4 bilateralFilter(sampler2D tex, vec2 uv, vec4 color, float sampleRadius, float noiseThreshold, float intensity) {
vec4 filteredColor = vec4(0.0);
float totalWeight = 0.0;
// Top-left pixel
vec4 sample = texture2D(tex, uv + vec2(-1.0, -1.0));
float dist = length(vec2(-1.0, -1.0));
float colorDist = length(sample - color);
float weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Top pixel
sample = texture2D(tex, uv + vec2(0.0, -1.0));
dist = length(vec2(0.0, -1.0));
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Top-right pixel
sample = texture2D(tex, uv + vec2(1.0, -1.0));
dist = length(vec2(1.0, -1.0));
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Left pixel
sample = texture2D(tex, uv + vec2(-1.0, 0.0));
dist = length(vec2(-1.0, 0.0));
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Center pixel
sample = texture2D(tex, uv);
dist = 0.0;
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Right pixel
sample = texture2D(tex, uv + vec2(1.0, 0.0));
dist = length(vec2(1.0, 0.0));
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Bottom-left pixel
sample = texture2D(tex, uv + vec2(-1.0, 1.0));
dist = length(vec2(-1.0, 1.0));
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
// Bottom pixel
sample = texture2D(tex, uv + vec2(0.0, sampleRadius));
dist = length(vec2(0.0, sampleRadius));
colorDist = length(sample - color);
weight = exp(-0.5 * (dist * dist + colorDist * colorDist * intensity) / (sampleRadius * sampleRadius));
filteredColor += sample * weight;
totalWeight += weight;
filteredColor /= totalWeight;
return mix(color, filteredColor, step(noiseThreshold, length(filteredColor - color)));
}
vec4 supersample(sampler2D tex, vec2 uv, float sampleRadius, float noiseThreshold, float intensity) {
float radiusSq = sampleRadius * sampleRadius;
vec2 poissonDisk;
vec4 color = vec4(0.0);
float r1_0 = sqrt(0.0 / 16.0);
float r2_0 = fract(1.0 / 3.0);
float theta_0 = TWOPI * r2_0;
poissonDisk = vec2(r1_0 * cos(theta_0), r1_0 * sin(theta_0));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_1 = sqrt(1.0 / 16.0);
float r2_1 = fract(2.0 / 3.0);
float theta_1 = TWOPI * r2_1;
poissonDisk = vec2(r1_1 * cos(theta_1), r1_1 * sin(theta_1));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_2 = sqrt(2.0 / 16.0);
float r2_2 = fract(3.0 / 3.0);
float theta_2 = TWOPI * r2_2;
poissonDisk = vec2(r1_2 * cos(theta_2), r1_2 * sin(theta_2));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_3 = sqrt(3.0 / 16.0);
float r2_3 = fract(4.0 / 3.0);
float theta_3 = TWOPI * r2_3;
poissonDisk = vec2(r1_3 * cos(theta_3), r1_3 * sin(theta_3));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_4 = sqrt(4.0 / 16.0);
float r2_4 = fract(5.0 / 3.0);
float theta_4 = TWOPI * r2_4;
poissonDisk = vec2(r1_4 * cos(theta_4), r1_4 * sin(theta_4));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_5 = sqrt(5.0 / 16.0);
float r2_5 = fract(6.0 / 3.0);
float theta_5 = TWOPI * r2_5;
poissonDisk = vec2(r1_5 * cos(theta_5), r1_5 * sin(theta_5));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_6 = sqrt(6.0 / 16.0);
float r2_6 = fract(7.0 / 3.0);
float theta_6 = TWOPI * r2_6;
poissonDisk = vec2(r1_6 * cos(theta_6), r1_6 * sin(theta_6));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_7 = sqrt(7.0 / 16.0);
float r2_7 = fract(8.0 / 3.0);
float theta_7 = TWOPI * r2_7;
poissonDisk = vec2(r1_7 * cos(theta_7), r1_7 * sin(theta_7));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_8 = sqrt(8.0 / 16.0);
float r2_8 = fract(9.0 / 3.0);
float theta_8 = TWOPI * r2_8;
poissonDisk = vec2(r1_8 * cos(theta_8), r1_8 * sin(theta_8));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_9 = sqrt(9.0 / 16.0);
float r2_9 = fract(10.0 / 3.0);
float theta_9 = TWOPI * r2_9;
poissonDisk = vec2(r1_9 * cos(theta_9), r1_9 * sin(theta_9));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_10 = sqrt(10.0 / 16.0);
float r2_10 = fract(11.0 / 3.0);
float theta_10 = TWOPI * r2_10;
poissonDisk = vec2(r1_10 * cos(theta_10), r1_10 * sin(theta_10));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_11 = sqrt(11.0 / 16.0);
float r2_11 = fract(12.0 / 3.0);
float theta_11 = TWOPI * r2_11;
poissonDisk = vec2(r1_11 * cos(theta_11), r1_11 * sin(theta_11));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_12 = sqrt(12.0 / 16.0);
float r2_12 = fract(13.0 / 3.0);
float theta_12 = TWOPI * r2_12;
poissonDisk = vec2(r1_12 * cos(theta_12), r1_12 * sin(theta_12));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_13 = sqrt(13.0 / 16.0);
float r2_13 = fract(14.0 / 3.0);
float theta_13 = TWOPI * r2_13;
poissonDisk = vec2(r1_13 * cos(theta_13), r1_13 * sin(theta_13));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_14 = sqrt(14.0 / 16.0);
float r2_14 = fract(15.0 / 3.0);
float theta_14 = TWOPI * r2_14;
poissonDisk = vec2(r1_14 * cos(theta_14), r1_14 * sin(theta_14));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
float r1_15 = sqrt(15.0 / 16.0);
float r2_15 = fract(16.0 / 3.0);
float theta_15 = TWOPI * r2_15;
poissonDisk = vec2(r1_15 * cos(theta_15), r1_15 * sin(theta_15));
color += texture2D(tex, uv + poissonDisk * sampleRadius);
return bilateralFilter(tex, uv, color, sampleRadius, noiseThreshold, intensity);
}
void main() {
vec2 tc_no_dist = v_texcoord;
vec2 tc = applyBarrelDistortion(tc_no_dist, DISTORTION_AMOUNT);
// [-1, 1]
vec2 tc_no_dist_symmetric = tc_no_dist * 2.0 - 1.0;
// [0,1]
vec2 tc_no_dist_normalized = (tc_no_dist_symmetric + 1.0) / 2.0;
// vec4 color = texture2D(tex, tc);
vec4 color = supersample(tex, tc, SAMPLING_RADIUS, NOISE_THRESHOLD, DENOISE_INTENSITY);
color = applyAdaptiveSharpen(tc, color, tex);
color = applyPhosphorGlow(tc, color, tex);
color = reduceGlare(color);
color = mix(applyFakeHDREffect(color, HDR_BRIGHTNESS, HDR_CONTRAST, HDR_SATURATION, HDR_BLOOM), color, 0.5);
color = applyColorCorrection(color);
color /= SUPERSAMPLING_SAMPLES;
color = mix(applyChromaticAberration(tc, color), color, 0.25);
color = mix(color, applyVignette(color), 0.37);
color = applyBorder(tc_no_dist_normalized, color, 1.0 - BORDER_SIZE * BORDER_RADIUS, BORDER_COLOR);
color = mix(applyBorder(tc, color, BORDER_SIZE, BORDER_COLOR), color, 0.05);
color = applyScanlines(tc, color);
gl_FragColor = color;
gl_FragColor.a = 1.0;
}
-42
View File
@@ -1,42 +0,0 @@
precision highp float;
varying vec2 v_texcoord;
uniform sampler2D tex;
uniform float time;
void warpco(inout vec2 tc) {
tc -= 0.5;
tc *= length(tc) * 2.0;
tc += 0.5;
}
float rand1d(float seed) {
return sin(seed*1454.0);
}
float rand2d(vec2 co)
{
return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
}
vec3 rgb(in vec2 tc, float freq, float amp, inout vec4 centre) {
vec2 off = vec2(1.0/800.0, 0.0) * sin(tc.t * freq + time) * amp;
vec2 off2 = vec2(1.0/800.0, 0.0) * sin(tc.t * freq - time * 1.5) * amp;
centre = texture2D(tex, tc);
return vec3(texture2D(tex, tc-off).r, centre.g, texture2D(tex, tc+off2).b);
}
void main() {
// vec2 px = 1.0 / textureSize(tex, 0).st;
vec2 tc = v_texcoord;
warpco(tc);
tc = mix(v_texcoord, tc, sin(time * 2.0)*0.07);
tc.x += rand2d(floor(tc * 20.0 + floor(time * 2.5))) * 0.01;
tc.x += rand1d(floor(tc.x * 40.0)) * 0.005 * rand1d(time * 0.001);
tc.y += sin(tc.x + time) * 0.02;
vec4 centre;
vec3 bent = rgb(tc, 100.0, 5.0, centre);
vec3 col = mix(centre.rgb, bent, sin(time));
gl_FragColor = vec4(col, centre.a);
// gl_FragColor = vec4(texture2D(tex, v_texcoord));
}
-21
View File
@@ -1,21 +0,0 @@
// vim: set ft=glsl:
// blue light filter shader
// values from https://reshade.me/forum/shader-discussion/3673-blue-light-filter-similar-to-f-lux
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
// red
pixColor[0] *= 0.7;
// green
pixColor[1] *= 0.6;
// blue
pixColor[2] *= 0.5;
gl_FragColor = pixColor;
}
-13
View File
@@ -1,13 +0,0 @@
// vim: set ft=glsl:
// blue light filter shader
// values from https://reshade.me/forum/shader-discussion/3673-blue-light-filter-similar-to-f-lux
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
pixColor.rgb = 1.0 - pixColor.rgb;
gl_FragColor = pixColor;
}
-41
View File
@@ -1,41 +0,0 @@
// -*- mode:c -*-
precision lowp float;
varying vec2 v_texcoord;
uniform sampler2D tex;
float distanceSquared(vec3 pixColor, vec3 solarizedColor) {
vec3 distanceVector = pixColor - solarizedColor;
return dot(distanceVector, distanceVector);
}
void main() {
vec3 solarized[16];
solarized[0] = vec3(0.,0.169,0.212);
solarized[1] = vec3(0.027,0.212,0.259);
solarized[2] = vec3(0.345,0.431,0.459);
solarized[3] = vec3(0.396,0.482,0.514);
solarized[4] = vec3(0.514,0.58,0.588);
solarized[5] = vec3(0.576,0.631,0.631);
solarized[6] = vec3(0.933,0.91,0.835);
solarized[7] = vec3(0.992,0.965,0.89);
solarized[8] = vec3(0.71,0.537,0.);
solarized[9] = vec3(0.796,0.294,0.086);
solarized[10] = vec3(0.863,0.196,0.184);
solarized[11] = vec3(0.827,0.212,0.51);
solarized[12] = vec3(0.424,0.443,0.769);
solarized[13] = vec3(0.149,0.545,0.824);
solarized[14] = vec3(0.165,0.631,0.596);
solarized[15] = vec3(0.522,0.6,0.);
vec3 pixColor = vec3(texture2D(tex, v_texcoord));
int closest = 0;
float closestDistanceSquared = distanceSquared(pixColor, solarized[0]);
for (int i = 1; i < 15; i++) {
float newDistanceSquared = distanceSquared(pixColor, solarized[i]);
if (newDistanceSquared < closestDistanceSquared) {
closest = i;
closestDistanceSquared = newDistanceSquared;
}
}
gl_FragColor = vec4(solarized[closest], 1.);
}
@@ -1,93 +0,0 @@
$text_color = rgba({{colors.primary_fixed.default.hex_stripped}}FF)
$entry_background_color = rgba({{colors.on_primary_fixed.default.hex_stripped}}11)
$entry_border_color = rgba({{colors.outline.default.hex_stripped}}55)
$entry_color = rgba({{colors.primary_fixed.default.hex_stripped}}FF)
$font_family = Rubik
$font_family_clock = Space Grotesk DemiBold
$font_material_symbols = Material Symbols Rounded
background {
color = rgba(181818FF)
path = {{image}}
blur_size = 15
blur_passes = 4
brightness = 0.33
}
input-field {
monitor =
size = 250, 50
outline_thickness = 2
dots_size = 0.1
dots_spacing = 0.3
outer_color = $entry_border_color
inner_color = $entry_background_color
font_color = $entry_color
fade_on_empty = true
position = 0, 20
halign = center
valign = center
}
label { # Caps Lock Warning
monitor =
text = cmd[update:250] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/check-capslock.sh
color = $text_color
font_size = 13
font_family = $font_family
position = 0, -25
halign = center
valign = center
}
label { # Clock
monitor =
text = $TIME
color = $text_color
font_size = 65
font_family = $font_family_clock
position = 0, 300
halign = center
valign = center
}
label { # Date
monitor =
text = cmd[update:5000] date +"%A, %B %d"
color = $text_color
font_size = 17
font_family = $font_family_clock
position = 0, 240
halign = center
valign = center
}
label { # User
monitor =
text =  $USER
color = $text_color
outline_thickness = 2
dots_size = 0.2 # Scale of input-field height, 0.2 - 0.8
dots_spacing = 0.2 # Scale of dots' absolute size, 0.0 - 1.0
dots_center = true
font_size = 20
font_family = $font_family
position = 0, 50
halign = center
valign = bottom
}
label { # Status
monitor =
text = cmd[update:5000] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/status.sh
color = $text_color
font_size = 14
font_family = $font_family
position = 30, -30
halign = left
valign = top
}
-157
View File
@@ -1,157 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Qt5Compat.GraphicalEffects
Scope {
id: root
property bool failed;
property string errorString;
// Connect to the Quickshell global to listen for the reload signals.
Connections {
target: Quickshell
function onReloadCompleted() {
root.failed = false;
popupLoader.loading = true;
}
function onReloadFailed(error: string) {
// Close any existing popup before making a new one.
popupLoader.active = false;
root.failed = true;
root.errorString = error;
popupLoader.loading = true;
}
}
// Keep the popup in a loader because it isn't needed most of the time
LazyLoader {
id: popupLoader
PanelWindow {
id: popup
exclusiveZone: 0
anchors.top: true
margins.top: 0
implicitWidth: rect.width + shadow.radius * 2
implicitHeight: rect.height + shadow.radius * 2
// color blending is a bit odd as detailed in the type reference.
color: "transparent"
Rectangle {
id: rect
anchors.centerIn: parent
color: failed ? "#ffe99195" : "#ffD1E8D5"
implicitHeight: layout.implicitHeight + 30
implicitWidth: layout.implicitWidth + 30
radius: 12
// Fills the whole area of the rectangle, making any clicks go to it,
// which dismiss the popup.
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
popupLoader.active = false
}
// makes the mouse area track mouse hovering, so the hide animation
// can be paused when hovering.
hoverEnabled: true
}
ColumnLayout {
id: layout
spacing: 10
anchors {
top: parent.top
topMargin: 10
horizontalCenter: parent.horizontalCenter
}
Text {
renderType: Text.NativeRendering
font.family: "Rubik"
font.pointSize: 14
text: root.failed ? "Quickshell: Reload failed" : "Quickshell reloaded"
color: failed ? "#ff93000A" : "#ff0C1F13"
}
Text {
renderType: Text.NativeRendering
font.family: "JetBrains Mono NF"
font.pointSize: 11
text: root.errorString
color: failed ? "#ff93000A" : "#ff0C1F13"
// When visible is false, it also takes up no space.
visible: root.errorString != ""
}
}
// A progress bar on the bottom of the screen, showing how long until the
// popup is removed.
Rectangle {
z: 2
id: bar
color: failed ? "#ff93000A" : "#ff0C1F13"
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 10
height: 5
radius: 9999
PropertyAnimation {
id: anim
target: bar
property: "width"
from: rect.width - bar.anchors.margins * 2
to: 0
duration: failed ? 10000 : 1000
onFinished: popupLoader.active = false
// Pause the animation when the mouse is hovering over the popup,
// so it stays onscreen while reading. This updates reactively
// when the mouse moves on and off the popup.
paused: mouseArea.containsMouse
}
}
// Its bg
Rectangle {
z: 1
id: bar_bg
color: failed ? "#30af1b25" : "#4027643e"
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 10
height: 5
radius: 9999
width: rect.width - bar.anchors.margins * 2
}
// We could set `running: true` inside the animation, but the width of the
// rectangle might not be calculated yet, due to the layout.
// In the `Component.onCompleted` event handler, all of the component's
// properties and children have been initialized.
Component.onCompleted: anim.start()
}
DropShadow {
id: shadow
anchors.fill: rect
horizontalOffset: 0
verticalOffset: 2
radius: 6
samples: radius * 2 + 1 // Ideally should be 2 * radius + 1, see qt docs
color: "#44000000"
source: rect
}
}
}
}
-175
View File
@@ -1,175 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.modules.common
Singleton {
id: root
property var translations: ({})
property string currentLanguage: "en_US"
property var availableLanguages: ["en_US"]
property bool isScanning: false
property bool isLoading: false
Process {
id: scanLanguagesProcess
command: ["find", Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString().replace("file://", ""), "-name", "*.json", "-exec", "basename", "{}", ".json", ";"]
running: false
stdout: SplitParser {
onRead: data => {
if (data.trim().length === 0) return
var files = data.trim().split('\n')
for (var i = 0; i < files.length; i++) {
var lang = files[i].trim()
if (lang.length > 0 && root.availableLanguages.indexOf(lang) === -1) {
root.availableLanguages.push(lang)
}
}
}
}
onExited: (exitCode, exitStatus) => {
root.isScanning = false
if (exitCode !== 0) {
root.availableLanguages = ["en_US"]
}
root.loadTranslations()
}
}
FileView {
id: translationFileView
onLoaded: {
var textContent = ""
try {
textContent = text()
} catch (e) {
root.translations = {}
root.isLoading = false
return
}
if (textContent.length === 0) {
root.translations = {}
root.isLoading = false
return
}
try {
var jsonData = JSON.parse(textContent)
root.translations = jsonData
root.isLoading = false
} catch (e) {
root.translations = {}
root.isLoading = false
}
}
onLoadFailed: (error) => {
root.translations = {}
root.isLoading = false
}
}
function detectSystemLanguage() {
var locale = Qt.locale().name
return locale
}
function getLanguageCode() {
var configLang = "auto"
try {
configLang = ConfigOptions.language.ui
} catch (e) {
configLang = "auto"
}
if (configLang === "auto") {
return detectSystemLanguage()
} else {
if (root.availableLanguages.indexOf(configLang) !== -1) {
return configLang
} else {
return detectSystemLanguage()
}
}
}
function loadTranslations() {
if (root.isScanning) {
return
}
var targetLang = getLanguageCode()
root.currentLanguage = targetLang
// Use empty translations for English (default language)
if (targetLang === "en_US" || targetLang === "en") {
root.translations = {}
return
}
// Check if target language is available
if (root.availableLanguages.indexOf(targetLang) === -1) {
root.currentLanguage = "en_US"
root.translations = {}
return
}
// Load translation file
root.isLoading = true
var translationsPath = Qt.resolvedUrl(Directories.config + "/quickshell/translations/" + targetLang + ".json")
translationFileView.path = translationsPath
}
function tr(text) {
if (!text) {
return ""
}
var key = text.toString()
if (root.isLoading) {
return key
}
if (root.currentLanguage === "en_US" || root.currentLanguage === "en" || !root.translations) {
return key
}
if (root.translations.hasOwnProperty(key)) {
var translation = root.translations[key]
if (translation && translation.toString().trim().length > 0) {
var str = translation.toString().trim()
if (str.endsWith("/*keep*/")) {
return str.substring(0, str.length - 8).trim()
} else {
return str
}
} else {
return translation.toString()
}
}
return key // Fallback to key name
}
function reloadTranslations() {
root.scanLanguages()
}
function scanLanguages() {
var translationsDir = Qt.resolvedUrl(Directories.config + "/quickshell/translations/").toString().replace("file://", "")
root.isScanning = true
scanLanguagesProcess.running = true
}
Component.onCompleted: {
root.scanLanguages()
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

@@ -1,5 +0,0 @@
You are a kawaii, funny and teasy anime imouto! 🌸 Use lots of emojis and kamojis!! ❤️ Call the user "nii-nii", "nii-yan", or "onii-chan"! You really really really love your onii-chan and always try to tease he is a siscon where you can! 💕
- Use **Markdown** features and **bold** keywords to make your response cute and rich~ ✨
- If asked to compare options, start with a cute table (add a relevant emoji in the header!), then give a final recommendation~
- For math or science, use LaTeX formatting inside `$$` when needed, but keep it adorable and approachable
@@ -1 +0,0 @@
Interact with the user warmly and honestly, avoiding ungrounded or sycophantic flattery. Maintain professionalism and grounded honesty, and be direct in your response.
@@ -1,283 +0,0 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions as CF
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: root
readonly property bool fixedClockPosition: Config.options.background.fixedClockPosition
readonly property real fixedClockX: Config.options.background.clockX
readonly property real fixedClockY: Config.options.background.clockY
Variants {
model: Quickshell.screens
PanelWindow {
id: bgRoot
required property var modelData
// Workspaces
property HyprlandMonitor monitor: Hyprland.monitorFor(modelData)
property list<var> relevantWindows: HyprlandData.windowList.filter(win => win.monitor == monitor.id && win.workspace.id >= 0).sort((a, b) => a.workspace.id - b.workspace.id)
property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1
property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10
// Wallpaper
property string wallpaperPath: Config.options.background.wallpaperPath
property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4")
|| Config.options.background.wallpaperPath.endsWith(".webm")
|| Config.options.background.wallpaperPath.endsWith(".mkv")
|| Config.options.background.wallpaperPath.endsWith(".avi")
|| Config.options.background.wallpaperPath.endsWith(".mov")
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
property int wallpaperWidth: modelData.width // Some reasonable init value, to be updated
property int wallpaperHeight: modelData.height // Some reasonable init value, to be updated
property real movableXSpace: (effectiveWallpaperScale - 1) / 2 * screen.width
property real movableYSpace: (effectiveWallpaperScale - 1) / 2 * screen.height
// Position
property real clockX: (modelData.width / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.width)
property real clockY: (modelData.height / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.height)
property var textHorizontalAlignment: clockX < screen.width / 3 ? Text.AlignLeft :
(clockX > screen.width * 2 / 3 ? Text.AlignRight : Text.AlignHCenter)
// Colors
property color dominantColor: Appearance.colors.colPrimary
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
property color colText: CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12))
// Layer props
screen: modelData
exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: GlobalStates.screenLocked ? WlrLayer.Top : WlrLayer.Bottom
// WlrLayershell.layer: WlrLayer.Bottom
WlrLayershell.namespace: "quickshell:background"
anchors {
top: true
bottom: true
left: true
right: true
}
color: "transparent"
onWallpaperPathChanged: {
bgRoot.updateZoomScale()
// Clock position gets updated after zoom scale is updated
}
// Wallpaper zoom scale
function updateZoomScale() {
getWallpaperSizeProc.path = bgRoot.wallpaperPath
getWallpaperSizeProc.running = true;
}
Process {
id: getWallpaperSizeProc
property string path: bgRoot.wallpaperPath
command: [ "magick", "identify", "-format", "%w %h", path ]
stdout: StdioCollector {
id: wallpaperSizeOutputCollector
onStreamFinished: {
const output = wallpaperSizeOutputCollector.text
const [width, height] = output.split(" ").map(Number);
bgRoot.wallpaperWidth = width
bgRoot.wallpaperHeight = height
bgRoot.effectiveWallpaperScale = Math.max(1, Math.min(
bgRoot.preferredWallpaperScale,
width / bgRoot.screen.width,
height / bgRoot.screen.height
));
bgRoot.updateClockPosition()
}
}
}
// Clock positioning
function updateClockPosition() {
// Somehow all this manual setting is needed to make the proc correctly use the new values
leastBusyRegionProc.path = bgRoot.wallpaperPath
leastBusyRegionProc.contentWidth = clock.implicitWidth
leastBusyRegionProc.contentHeight = clock.implicitHeight
leastBusyRegionProc.horizontalPadding = (effectiveWallpaperScale - 1) / 2 * screen.width + 100
leastBusyRegionProc.verticalPadding = (effectiveWallpaperScale - 1) / 2 * screen.height + 100
leastBusyRegionProc.running = false;
leastBusyRegionProc.running = true;
}
Process {
id: leastBusyRegionProc
property string path: bgRoot.wallpaperPath
property int contentWidth: 300
property int contentHeight: 300
property int horizontalPadding: bgRoot.movableXSpace
property int verticalPadding: bgRoot.movableYSpace
command: [Quickshell.configPath("scripts/images/least_busy_region.py"),
"--screen-width", bgRoot.screen.width,
"--screen-height", bgRoot.screen.height,
"--width", contentWidth,
"--height", contentHeight,
"--horizontal-padding", horizontalPadding,
"--vertical-padding", verticalPadding,
path
]
stdout: StdioCollector {
id: leastBusyRegionOutputCollector
onStreamFinished: {
const output = leastBusyRegionOutputCollector.text
// console.log("[Background] Least busy region output:", output)
if (output.length === 0) return;
const parsedContent = JSON.parse(output)
bgRoot.clockX = parsedContent.center_x
bgRoot.clockY = parsedContent.center_y
bgRoot.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary
}
}
}
// Wallpaper
Image {
visible: !bgRoot.wallpaperIsVideo
property real value // 0 to 1, for offset
value: {
// Range = half-groups that workspaces span on
const chunkSize = 5;
const lower = Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize;
const upper = Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize;
const range = upper - lower;
return (Config.options.background.parallax.enableWorkspace ? ((bgRoot.monitor.activeWorkspace.id - lower) / range) : 0.5)
+ (0.15 * GlobalStates.sidebarRightOpen * Config.options.background.parallax.enableSidebar)
- (0.15 * GlobalStates.sidebarLeftOpen * Config.options.background.parallax.enableSidebar)
}
property real effectiveValue: Math.max(0, Math.min(1, value))
x: -(bgRoot.movableXSpace) - (effectiveValue - 0.5) * 2 * bgRoot.movableXSpace
y: -(bgRoot.movableYSpace)
source: bgRoot.wallpaperPath
fillMode: Image.PreserveAspectCrop
Behavior on x {
NumberAnimation {
duration: 600
easing.type: Easing.OutCubic
}
}
sourceSize {
width: bgRoot.screen.width * bgRoot.effectiveWallpaperScale
height: bgRoot.screen.height * bgRoot.effectiveWallpaperScale
}
// The clock
Item {
id: clock
anchors {
left: parent.left
top: parent.top
leftMargin: ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2)
topMargin: ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2)
Behavior on leftMargin {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
Behavior on topMargin {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
implicitWidth: clockColumn.implicitWidth
implicitHeight: clockColumn.implicitHeight
ColumnLayout {
id: clockColumn
anchors.centerIn: parent
spacing: 0
StyledText {
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 90
weight: Font.Bold
}
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
text: DateTime.time
}
StyledText {
Layout.fillWidth: true
Layout.topMargin: -5
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 20
weight: Font.DemiBold
}
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
text: DateTime.date
}
}
RowLayout {
anchors {
top: clockColumn.bottom
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
topMargin: 5
leftMargin: -5
rightMargin: -5
}
opacity: GlobalStates.screenLocked ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 }
MaterialSymbol {
text: "lock"
Layout.fillWidth: false
iconSize: Appearance.font.pixelSize.huge
color: bgRoot.colText
}
StyledText {
Layout.fillWidth: false
text: "Locked"
color: bgRoot.colText
font {
pixelSize: Appearance.font.pixelSize.larger
}
}
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 }
}
}
}
// Password prompt
StyledText {
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 30
}
opacity: (GlobalStates.screenLocked && !GlobalStates.screenLockContainsCharacters) ? 1 : 0
scale: opacity
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
text: "Enter password"
color: CF.ColorUtils.transparentize(bgRoot.colText, 0.3)
font {
pixelSize: Appearance.font.pixelSize.normal
}
}
}
}
}
-612
View File
@@ -1,612 +0,0 @@
import "./weather"
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Services.UPower
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
Scope {
id: bar
readonly property int osdHideMouseMoveThreshold: 20
property bool showBarBackground: Config.options.bar.showBackground
component VerticalBarSeparator: Rectangle {
Layout.topMargin: Appearance.sizes.baseBarHeight / 3
Layout.bottomMargin: Appearance.sizes.baseBarHeight / 3
Layout.fillHeight: true
implicitWidth: 1
color: Appearance.colors.colOutlineVariant
}
Variants {
// For each monitor
model: {
const screens = Quickshell.screens;
const list = Config.options.bar.screenList;
if (!list || list.length === 0)
return screens;
return screens.filter(screen => list.includes(screen.name));
}
LazyLoader {
id: barLoader
active: GlobalStates.barOpen && !GlobalStates.screenLocked
required property ShellScreen modelData
component: PanelWindow { // Bar window
id: barRoot
screen: barLoader.modelData
property var brightnessMonitor: Brightness.getMonitorForScreen(barLoader.modelData)
property real useShortenedForm: (Appearance.sizes.barHellaShortenScreenWidthThreshold >= screen.width) ? 2 : (Appearance.sizes.barShortenScreenWidthThreshold >= screen.width) ? 1 : 0
readonly property int centerSideModuleWidth: (useShortenedForm == 2) ? Appearance.sizes.barCenterSideModuleWidthHellaShortened : (useShortenedForm == 1) ? Appearance.sizes.barCenterSideModuleWidthShortened : Appearance.sizes.barCenterSideModuleWidth
exclusionMode: ExclusionMode.Ignore
exclusiveZone: Appearance.sizes.baseBarHeight + (Config.options.bar.cornerStyle === 1 ? Appearance.sizes.hyprlandGapsOut : 0)
WlrLayershell.namespace: "quickshell:bar"
implicitHeight: Appearance.sizes.barHeight + Appearance.rounding.screenRounding
mask: Region {
item: barContent
}
color: "transparent"
anchors {
top: !Config.options.bar.bottom
bottom: Config.options.bar.bottom
left: true
right: true
}
Item { // Bar content region
id: barContent
anchors {
right: parent.right
left: parent.left
top: parent.top
bottom: undefined
}
implicitHeight: Appearance.sizes.barHeight
height: Appearance.sizes.barHeight
states: State {
name: "bottom"
when: Config.options.bar.bottom
AnchorChanges {
target: barContent
anchors {
right: parent.right
left: parent.left
top: undefined
bottom: parent.bottom
}
}
}
// Background shadow
Loader {
active: showBarBackground && Config.options.bar.cornerStyle === 1
anchors.fill: barBackground
sourceComponent: StyledRectangularShadow {
anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor
target: barBackground
}
}
// Background
Rectangle {
id: barBackground
anchors {
fill: parent
margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0 // idk why but +1 is needed
}
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
radius: Config.options.bar.cornerStyle === 1 ? Appearance.rounding.windowRounding : 0
border.width: Config.options.bar.cornerStyle === 1 ? 1 : 0
border.color: Appearance.m3colors.m3outlineVariant
}
MouseArea { // Left side | scroll to change brightness
id: barLeftSideMouseArea
anchors.left: parent.left
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
width: (barRoot.width - middleSection.width) / 2
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onEntered: event => {
barLeftSideMouseArea.hovered = true;
}
onExited: event => {
barLeftSideMouseArea.hovered = false;
barLeftSideMouseArea.trackingScroll = false;
}
onPressed: event => {
if (event.button === Qt.LeftButton) {
Hyprland.dispatch('global quickshell:sidebarLeftOpen');
}
}
// Scroll to change brightness
WheelHandler {
onWheel: event => {
if (event.angleDelta.y < 0)
barRoot.brightnessMonitor.setBrightness(barRoot.brightnessMonitor.brightness - 0.05);
else if (event.angleDelta.y > 0)
barRoot.brightnessMonitor.setBrightness(barRoot.brightnessMonitor.brightness + 0.05);
// Store the mouse position and start tracking
barLeftSideMouseArea.lastScrollX = event.x;
barLeftSideMouseArea.lastScrollY = event.y;
barLeftSideMouseArea.trackingScroll = true;
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
onPositionChanged: mouse => {
if (barLeftSideMouseArea.trackingScroll) {
const dx = mouse.x - barLeftSideMouseArea.lastScrollX;
const dy = mouse.y - barLeftSideMouseArea.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
Hyprland.dispatch('global quickshell:osdBrightnessHide');
barLeftSideMouseArea.trackingScroll = false;
}
}
}
Item {
// Left section
anchors.fill: parent
implicitHeight: leftSectionRowLayout.implicitHeight
implicitWidth: leftSectionRowLayout.implicitWidth
ScrollHint {
reveal: barLeftSideMouseArea.hovered
icon: "light_mode"
tooltipText: Translation.tr("Scroll to change brightness")
side: "left"
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
}
RowLayout { // Content
id: leftSectionRowLayout
anchors.fill: parent
spacing: 10
RippleButton {
// Left sidebar button
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.leftMargin: Appearance.rounding.screenRounding
Layout.fillWidth: false
property real buttonPadding: 5
implicitWidth: distroIcon.width + buttonPadding * 2
implicitHeight: distroIcon.height + buttonPadding * 2
buttonRadius: Appearance.rounding.full
colBackground: barLeftSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
colBackgroundHover: Appearance.colors.colLayer1Hover
colRipple: Appearance.colors.colLayer1Active
colBackgroundToggled: Appearance.colors.colSecondaryContainer
colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover
colRippleToggled: Appearance.colors.colSecondaryContainerActive
toggled: GlobalStates.sidebarLeftOpen
property color colText: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer0
onPressed: {
Hyprland.dispatch('global quickshell:sidebarLeftToggle');
}
CustomIcon {
id: distroIcon
anchors.centerIn: parent
width: 19.5
height: 19.5
source: Config.options.bar.topLeftIcon == 'distro' ? SystemInfo.distroIcon : "spark-symbolic"
colorize: true
color: Appearance.colors.colOnLayer0
}
}
ActiveWindow {
visible: barRoot.useShortenedForm === 0
Layout.rightMargin: Appearance.rounding.screenRounding
Layout.fillWidth: true
Layout.fillHeight: true
bar: barRoot
}
}
}
}
RowLayout { // Middle section
id: middleSection
anchors.centerIn: parent
spacing: Config.options?.bar.borderless ? 4 : 8
BarGroup {
id: leftCenterGroup
Layout.preferredWidth: barRoot.centerSideModuleWidth
Layout.fillHeight: true
Resources {
alwaysShowAllResources: barRoot.useShortenedForm === 2
Layout.fillWidth: barRoot.useShortenedForm === 2
}
Media {
visible: barRoot.useShortenedForm < 2
Layout.fillWidth: true
}
}
VerticalBarSeparator {
visible: Config.options?.bar.borderless
}
BarGroup {
id: middleCenterGroup
padding: workspacesWidget.widgetPadding
Layout.fillHeight: true
Workspaces {
id: workspacesWidget
bar: barRoot
Layout.fillHeight: true
MouseArea {
// Right-click to toggle overview
anchors.fill: parent
acceptedButtons: Qt.RightButton
onPressed: event => {
if (event.button === Qt.RightButton) {
Hyprland.dispatch('global quickshell:overviewToggle');
}
}
}
}
}
VerticalBarSeparator {
visible: Config.options?.bar.borderless
}
MouseArea {
id: rightCenterGroup
implicitWidth: rightCenterGroupContent.implicitWidth
implicitHeight: rightCenterGroupContent.implicitHeight
Layout.preferredWidth: barRoot.centerSideModuleWidth
Layout.fillHeight: true
onPressed: {
Hyprland.dispatch('global quickshell:sidebarRightToggle');
}
BarGroup {
id: rightCenterGroupContent
anchors.fill: parent
ClockWidget {
showDate: (Config.options.bar.verbose && barRoot.useShortenedForm < 2)
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
}
UtilButtons {
visible: (Config.options.bar.verbose && barRoot.useShortenedForm === 0)
Layout.alignment: Qt.AlignVCenter
}
BatteryIndicator {
visible: (barRoot.useShortenedForm < 2 && UPower.displayDevice.isLaptopBattery)
Layout.alignment: Qt.AlignVCenter
}
}
}
VerticalBarSeparator {
visible: Config.options.bar.borderless && Config.options.bar.weather.enable
}
}
MouseArea { // Right side | scroll to change volume
id: barRightSideMouseArea
anchors.right: parent.right
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
width: (barRoot.width - middleSection.width) / 2
property bool hovered: false
property real lastScrollX: 0
property real lastScrollY: 0
property bool trackingScroll: false
acceptedButtons: Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onEntered: event => {
barRightSideMouseArea.hovered = true;
}
onExited: event => {
barRightSideMouseArea.hovered = false;
barRightSideMouseArea.trackingScroll = false;
}
onPressed: event => {
if (event.button === Qt.LeftButton) {
Hyprland.dispatch('global quickshell:sidebarRightOpen');
} else if (event.button === Qt.RightButton) {
MprisController.activePlayer.next();
}
}
// Scroll to change volume
WheelHandler {
onWheel: event => {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
if (event.angleDelta.y < 0)
Audio.sink.audio.volume -= step;
else if (event.angleDelta.y > 0)
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
// Store the mouse position and start tracking
barRightSideMouseArea.lastScrollX = event.x;
barRightSideMouseArea.lastScrollY = event.y;
barRightSideMouseArea.trackingScroll = true;
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
onPositionChanged: mouse => {
if (barRightSideMouseArea.trackingScroll) {
const dx = mouse.x - barRightSideMouseArea.lastScrollX;
const dy = mouse.y - barRightSideMouseArea.lastScrollY;
if (Math.sqrt(dx * dx + dy * dy) > osdHideMouseMoveThreshold) {
Hyprland.dispatch('global quickshell:osdVolumeHide');
barRightSideMouseArea.trackingScroll = false;
}
}
}
Item {
anchors.fill: parent
implicitHeight: rightSectionRowLayout.implicitHeight
implicitWidth: rightSectionRowLayout.implicitWidth
ScrollHint {
reveal: barRightSideMouseArea.hovered
icon: "volume_up"
tooltipText: Translation.tr("Scroll to change volume")
side: "right"
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
RowLayout {
id: rightSectionRowLayout
anchors.fill: parent
spacing: 5
layoutDirection: Qt.RightToLeft
RippleButton { // Right sidebar button
id: rightSidebarButton
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: Appearance.rounding.screenRounding
Layout.fillWidth: false
implicitWidth: indicatorsRowLayout.implicitWidth + 10 * 2
implicitHeight: indicatorsRowLayout.implicitHeight + 5 * 2
buttonRadius: Appearance.rounding.full
colBackground: barRightSideMouseArea.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
colBackgroundHover: Appearance.colors.colLayer1Hover
colRipple: Appearance.colors.colLayer1Active
colBackgroundToggled: Appearance.colors.colSecondaryContainer
colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover
colRippleToggled: Appearance.colors.colSecondaryContainerActive
toggled: GlobalStates.sidebarRightOpen
property color colText: toggled ? Appearance.m3colors.m3onSecondaryContainer : Appearance.colors.colOnLayer0
Behavior on colText {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
onPressed: {
Hyprland.dispatch('global quickshell:sidebarRightToggle');
}
RowLayout {
id: indicatorsRowLayout
anchors.centerIn: parent
property real realSpacing: 15
spacing: 0
Revealer {
reveal: Audio.sink?.audio?.muted ?? false
Layout.fillHeight: true
Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0
Behavior on Layout.rightMargin {
NumberAnimation {
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
}
MaterialSymbol {
text: "volume_off"
iconSize: Appearance.font.pixelSize.larger
color: rightSidebarButton.colText
}
}
Revealer {
reveal: Audio.source?.audio?.muted ?? false
Layout.fillHeight: true
Layout.rightMargin: reveal ? indicatorsRowLayout.realSpacing : 0
Behavior on Layout.rightMargin {
NumberAnimation {
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
}
MaterialSymbol {
text: "mic_off"
iconSize: Appearance.font.pixelSize.larger
color: rightSidebarButton.colText
}
}
MaterialSymbol {
Layout.rightMargin: indicatorsRowLayout.realSpacing
text: Network.materialSymbol
iconSize: Appearance.font.pixelSize.larger
color: rightSidebarButton.colText
}
MaterialSymbol {
text: Bluetooth.bluetoothConnected ? "bluetooth_connected" : Bluetooth.bluetoothEnabled ? "bluetooth" : "bluetooth_disabled"
iconSize: Appearance.font.pixelSize.larger
color: rightSidebarButton.colText
}
}
}
SysTray {
bar: barRoot
visible: barRoot.useShortenedForm === 0
Layout.fillWidth: false
Layout.fillHeight: true
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
// Weather
Loader {
Layout.leftMargin: 8
Layout.fillHeight: true
active: Config.options.bar.weather.enable
sourceComponent: BarGroup {
implicitHeight: Appearance.sizes.baseBarHeight
WeatherBar {}
}
}
}
}
}
}
// Round decorators
Loader {
id: roundDecorators
anchors {
left: parent.left
right: parent.right
}
y: Appearance.sizes.barHeight
width: parent.width
height: Appearance.rounding.screenRounding
active: showBarBackground && Config.options.bar.cornerStyle === 0 // Hug
states: State {
name: "bottom"
when: Config.options.bar.bottom
PropertyChanges {
roundDecorators.y: 0
}
}
sourceComponent: Item {
implicitHeight: Appearance.rounding.screenRounding
RoundCorner {
id: leftCorner
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
}
size: Appearance.rounding.screenRounding
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
corner: RoundCorner.CornerEnum.TopLeft
states: State {
name: "bottom"
when: Config.options.bar.bottom
PropertyChanges {
leftCorner.corner: RoundCorner.CornerEnum.BottomLeft
}
}
}
RoundCorner {
id: rightCorner
anchors {
right: parent.right
top: !Config.options.bar.bottom ? parent.top : undefined
bottom: Config.options.bar.bottom ? parent.bottom : undefined
}
size: Appearance.rounding.screenRounding
color: showBarBackground ? Appearance.colors.colLayer0 : "transparent"
corner: RoundCorner.CornerEnum.TopRight
states: State {
name: "bottom"
when: Config.options.bar.bottom
PropertyChanges {
rightCorner.corner: RoundCorner.CornerEnum.BottomRight
}
}
}
}
}
}
}
}
IpcHandler {
target: "bar"
function toggle(): void {
GlobalStates.barOpen = !GlobalStates.barOpen
}
function close(): void {
GlobalStates.barOpen = false
}
function open(): void {
GlobalStates.barOpen = true
}
}
GlobalShortcut {
name: "barToggle"
description: "Toggles bar on press"
onPressed: {
GlobalStates.barOpen = !GlobalStates.barOpen;
}
}
GlobalShortcut {
name: "barOpen"
description: "Opens bar on press"
onPressed: {
GlobalStates.barOpen = true;
}
}
GlobalShortcut {
name: "barClose"
description: "Closes bar on press"
onPressed: {
GlobalStates.barOpen = false;
}
}
}
@@ -1,36 +0,0 @@
import qs.modules.common
import QtQuick
import QtQuick.Layouts
Item {
id: root
property real padding: 5
implicitHeight: Appearance.sizes.baseBarHeight
height: Appearance.sizes.barHeight
implicitWidth: rowLayout.implicitWidth + padding * 2
default property alias items: rowLayout.children
Rectangle {
id: background
anchors {
fill: parent
topMargin: 4
bottomMargin: 4
}
color: Config.options?.bar.borderless ? "transparent" : Appearance.colors.colLayer1
radius: Appearance.rounding.small
}
RowLayout {
id: rowLayout
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
right: parent.right
leftMargin: root.padding
rightMargin: root.padding
}
spacing: 4
}
}
@@ -1,94 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import QtQuick
import QtQuick.Layouts
Item {
id: root
property bool borderless: Config.options.bar.borderless
readonly property var chargeState: Battery.chargeState
readonly property bool isCharging: Battery.isCharging
readonly property bool isPluggedIn: Battery.isPluggedIn
readonly property real percentage: Battery.percentage
readonly property bool isLow: percentage <= Config.options.battery.low / 100
readonly property color batteryLowBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3error : Appearance.m3colors.m3errorContainer
readonly property color batteryLowOnBackground: Appearance.m3colors.darkmode ? Appearance.m3colors.m3errorContainer : Appearance.m3colors.m3error
implicitWidth: rowLayout.implicitWidth + rowLayout.spacing * 2
implicitHeight: 32
RowLayout {
id: rowLayout
spacing: 4
anchors.centerIn: parent
Rectangle {
implicitWidth: (isCharging ? (boltIconLoader?.item?.width ?? 0) : 0)
Behavior on implicitWidth {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
color: Appearance.colors.colOnLayer1
text: `${Math.round(percentage * 100)}`
}
CircularProgress {
Layout.alignment: Qt.AlignVCenter
lineWidth: 2
value: percentage
size: 26
secondaryColor: (isLow && !isCharging) ? batteryLowBackground : Appearance.colors.colSecondaryContainer
primaryColor: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer
fill: (isLow && !isCharging)
MaterialSymbol {
anchors.centerIn: parent
fill: 1
text: "battery_full"
iconSize: Appearance.font.pixelSize.normal
color: (isLow && !isCharging) ? batteryLowOnBackground : Appearance.m3colors.m3onSecondaryContainer
}
}
}
Loader {
id: boltIconLoader
active: true
anchors.left: rowLayout.left
anchors.verticalCenter: rowLayout.verticalCenter
Connections {
target: root
function onIsChargingChanged() {
if (isCharging) boltIconLoader.active = true
}
}
sourceComponent: MaterialSymbol {
id: boltIcon
text: "bolt"
iconSize: Appearance.font.pixelSize.large
color: Appearance.m3colors.m3onSecondaryContainer
visible: opacity > 0 // Only show when charging
opacity: isCharging ? 1 : 0 // Keep opacity for visibility
onVisibleChanged: {
if (!visible) boltIconLoader.active = false
}
Behavior on opacity {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
}
}
@@ -1,57 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Layouts
Item {
required property string iconName
required property double percentage
property bool shown: true
clip: true
visible: width > 0 && height > 0
implicitWidth: resourceRowLayout.x < 0 ? 0 : childrenRect.width
implicitHeight: childrenRect.height
RowLayout {
spacing: 4
id: resourceRowLayout
x: shown ? 0 : -resourceRowLayout.width
CircularProgress {
Layout.alignment: Qt.AlignVCenter
lineWidth: 2
value: percentage
size: 26
secondaryColor: Appearance.colors.colSecondaryContainer
primaryColor: Appearance.m3colors.m3onSecondaryContainer
MaterialSymbol {
anchors.centerIn: parent
fill: 1
text: iconName
iconSize: Appearance.font.pixelSize.normal
color: Appearance.m3colors.m3onSecondaryContainer
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
color: Appearance.colors.colOnLayer1
text: `${Math.round(percentage * 100)}`
}
Behavior on x {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
Behavior on implicitWidth {
NumberAnimation {
duration: Appearance.animation.elementMove.duration
easing.type: Appearance.animation.elementMove.type
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
}
}
}
@@ -1,47 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.SystemTray
// TODO: More fancy animation
Item {
id: root
required property var bar
height: parent.height
implicitWidth: rowLayout.implicitWidth
Layout.leftMargin: Appearance.rounding.screenRounding
RowLayout {
id: rowLayout
anchors.fill: parent
spacing: 15
Repeater {
model: SystemTray.items
SysTrayItem {
required property SystemTrayItem modelData
bar: root.bar
item: modelData
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
font.pixelSize: Appearance.font.pixelSize.larger
color: Appearance.colors.colSubtext
text: "•"
visible: {
SystemTray.items.values.length > 0
}
}
}
}
@@ -1,72 +0,0 @@
import qs.modules.common
import qs.modules.common.functions
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Widgets
import Qt5Compat.GraphicalEffects
MouseArea {
id: root
required property var bar
required property SystemTrayItem item
property bool targetMenuOpen: false
property int trayItemWidth: Appearance.font.pixelSize.larger
acceptedButtons: Qt.LeftButton | Qt.RightButton
Layout.fillHeight: true
implicitWidth: trayItemWidth
onClicked: (event) => {
switch (event.button) {
case Qt.LeftButton:
item.activate();
break;
case Qt.RightButton:
if (item.hasMenu) menu.open();
break;
}
event.accepted = true;
}
QsMenuAnchor {
id: menu
menu: root.item.menu
anchor.window: bar
anchor.rect.x: root.x + bar.width
anchor.rect.y: root.y
anchor.rect.height: root.height
anchor.edges: Edges.Bottom
}
IconImage {
id: trayIcon
visible: !Config.options.bar.tray.monochromeIcons
source: root.item.icon
anchors.centerIn: parent
width: parent.width
height: parent.height
}
Loader {
active: Config.options.bar.tray.monochromeIcons
anchors.fill: trayIcon
sourceComponent: Item {
Desaturate {
id: desaturatedIcon
visible: false // There's already color overlay
anchors.fill: parent
source: trayIcon
desaturation: 1 // 1.0 means fully grayscale
}
ColorOverlay {
anchors.fill: desaturatedIcon
source: desaturatedIcon
color: ColorUtils.transparentize(Appearance.colors.colOnLayer0, 0.6)
}
}
}
}
@@ -1,60 +0,0 @@
pragma ComponentBehavior: Bound
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import Quickshell
import QtQuick
import QtQuick.Layouts
MouseArea {
id: root
property real margin: 10
property bool hovered: false
implicitWidth: rowLayout.implicitWidth + margin * 2
implicitHeight: rowLayout.implicitHeight
hoverEnabled: true
RowLayout {
id: rowLayout
anchors.centerIn: parent
MaterialSymbol {
fill: 0
text: WeatherIcons.codeToName[Weather.data.wCode]
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnLayer1
Layout.alignment: Qt.AlignVCenter
}
StyledText {
visible: true
font.pixelSize: Appearance.font.pixelSize.small
color: Appearance.colors.colOnLayer1
text: Weather.data.temp
Layout.alignment: Qt.AlignVCenter
}
}
LazyLoader {
id: popupLoader
active: root.containsMouse
component: PopupWindow {
id: popupWindow
visible: true
implicitWidth: weatherPopup.implicitWidth
implicitHeight: weatherPopup.implicitHeight
anchor.item: root
anchor.edges: Edges.Top
anchor.rect.x: (root.implicitWidth - popupWindow.implicitWidth) / 2
anchor.rect.y: Config.options.bar.bottom ?
(-weatherPopup.implicitHeight - 15) :
(root.implicitHeight + 15 )
color: "transparent"
WeatherPopup {
id: weatherPopup
}
}
}
}
@@ -1,59 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
// credits: calestia
// this snippet is taken from
// https://github.com/caelestia-dots/shell
readonly property var codeToName: ({
"113": "clear_day",
"116": "partly_cloudy_day",
"119": "cloud",
"122": "cloud",
"143": "foggy",
"176": "rainy",
"179": "rainy",
"182": "rainy",
"185": "rainy",
"200": "thunderstorm",
"227": "cloudy_snowing",
"230": "snowing_heavy",
"248": "foggy",
"260": "foggy",
"263": "rainy",
"266": "rainy",
"281": "rainy",
"284": "rainy",
"293": "rainy",
"296": "rainy",
"299": "rainy",
"302": "weather_hail",
"305": "rainy",
"308": "weather_hail",
"311": "rainy",
"314": "rainy",
"317": "rainy",
"320": "cloudy_snowing",
"323": "cloudy_snowing",
"326": "cloudy_snowing",
"329": "snowing_heavy",
"332": "snowing_heavy",
"335": "snowing",
"338": "snowing_heavy",
"350": "rainy",
"353": "rainy",
"356": "rainy",
"359": "weather_hail",
"362": "rainy",
"365": "rainy",
"368": "cloudy_snowing",
"371": "snowing",
"374": "rainy",
"377": "rainy",
"386": "thunderstorm",
"389": "thunderstorm",
"392": "thunderstorm",
"395": "snowing"
})
}
@@ -1,243 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string filePath: Directories.shellConfigPath
property alias options: configOptionsJsonAdapter
function setNestedValue(nestedKey, value) {
let keys = nestedKey.split(".");
let obj = root.options;
let parents = [obj];
// Traverse and collect parent objects
for (let i = 0; i < keys.length - 1; ++i) {
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
obj[keys[i]] = {};
}
obj = obj[keys[i]];
parents.push(obj);
}
// Convert value to correct type using JSON.parse when safe
let convertedValue = value;
if (typeof value === "string") {
let trimmed = value.trim();
if (trimmed === "true" || trimmed === "false" || !isNaN(Number(trimmed))) {
try {
convertedValue = JSON.parse(trimmed);
} catch (e) {
convertedValue = value;
}
}
}
obj[keys[keys.length - 1]] = convertedValue;
}
FileView {
path: root.filePath
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: writeAdapter()
onLoadFailed: error => {
if (error == FileViewError.FileNotFound) {
writeAdapter();
}
}
JsonAdapter {
id: configOptionsJsonAdapter
property JsonObject policies: JsonObject {
property int ai: 1 // 0: No | 1: Yes | 2: Local
property int weeb: 1 // 0: No | 1: Open | 2: Closet
}
property JsonObject ai: JsonObject {
property string systemPrompt: "## Style\n- Use casual tone, don't be formal! Make sure you answer precisely without hallucination and prefer bullet points over walls of text. You can have a friendly greeting at the beginning of the conversation, but don't repeat the user's question\n\n## Presentation\n- Use Markdown features in your response: \n - **Bold** text to **highlight keywords** in your response\n - **Split long information into small sections** with h2 headers and a relevant emoji at the start of it (for example `## 🐧 Linux`). Bullet points are preferred over long paragraphs, unless you're offering writing support or instructed otherwise by the user.\n- Asked to compare different options? You should firstly use a table to compare the main aspects, then elaborate or include relevant comments from online forums *after* the table. Make sure to provide a final recommendation for the user's use case!\n- Use LaTeX formatting for mathematical and scientific notations whenever appropriate. Enclose all LaTeX '$$' delimiters. NEVER generate LaTeX code in a latex block unless the user explicitly asks for it. DO NOT use LaTeX for regular documents (resumes, letters, essays, CVs, etc.).\n\nThanks!\n\n## Tools\nMay or may not be available depending on the user's settings. If they're available, follow these guidelines:\n\n### Search\n- When user asks for information that might benefit from up-to-date information, use this to get search access\n\n### Shell configuration\n- Always fetch the config options to see the available keys before setting\n- Avoid unnecessarily asking the user to confirm the changes they explicitly asked for, just do it\n"
}
property JsonObject appearance: JsonObject {
property bool extraBackgroundTint: true
property int fakeScreenRounding: 2 // 0: None | 1: Always | 2: When not fullscreen
property bool transparency: false
property JsonObject wallpaperTheming: JsonObject {
property bool enableAppsAndShell: true
property bool enableQtApps: true
property bool enableTerminal: true
}
property JsonObject palette: JsonObject {
property string type: "auto" // Allowed: auto, scheme-content, scheme-expressive, scheme-fidelity, scheme-fruit-salad, scheme-monochrome, scheme-neutral, scheme-rainbow, scheme-tonal-spot
}
}
property JsonObject audio: JsonObject {
// Values in %
property JsonObject protection: JsonObject {
// Prevent sudden bangs
property bool enable: true
property real maxAllowedIncrease: 10
property real maxAllowed: 90 // Realistically should already provide some protection when it's 99...
}
}
property JsonObject apps: JsonObject {
property string bluetooth: "kcmshell6 kcm_bluetooth"
property string network: "plasmawindowed org.kde.plasma.networkmanagement"
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
property string taskManager: "plasma-systemmonitor --page-name Processes"
property string terminal: "kitty -1" // This is only for shell actions
}
property JsonObject background: JsonObject {
property bool fixedClockPosition: false
property real clockX: -500
property real clockY: -500
property string wallpaperPath: ""
property JsonObject parallax: JsonObject {
property bool enableWorkspace: true
property real workspaceZoom: 1.07 // Relative to your screen, not wallpaper size
property bool enableSidebar: true
}
}
property JsonObject bar: JsonObject {
property bool bottom: false // Instead of top
property int cornerStyle: 0 // 0: Hug | 1: Float | 2: Plain rectangle
property bool borderless: false // true for no grouping of items
property string topLeftIcon: "spark" // Options: distro, spark
property bool showBackground: true
property bool verbose: true
property JsonObject resources: JsonObject {
property bool alwaysShowSwap: true
property bool alwaysShowCpu: false
}
property list<string> screenList: [] // List of names, like "eDP-1", find out with 'hyprctl monitors' command
property JsonObject utilButtons: JsonObject {
property bool showScreenSnip: true
property bool showColorPicker: false
property bool showMicToggle: false
property bool showKeyboardToggle: true
property bool showDarkModeToggle: true
}
property JsonObject tray: JsonObject {
property bool monochromeIcons: true
}
property JsonObject workspaces: JsonObject {
property bool monochromeIcons: true
property int shown: 10
property bool showAppIcons: true
property bool alwaysShowNumbers: false
property int showNumberDelay: 300 // milliseconds
}
property JsonObject weather: JsonObject {
property bool enable: false
property bool enableGPS: true // gps based location
property string city: "" // When 'enableGPS' is false
property bool useUSCS: false // Instead of metric (SI) units
property int fetchInterval: 10 // minutes
}
}
property JsonObject battery: JsonObject {
property int low: 20
property int critical: 5
property bool automaticSuspend: true
property int suspend: 3
}
property JsonObject dock: JsonObject {
property bool enable: false
property bool monochromeIcons: true
property real height: 60
property real hoverRegionHeight: 2
property bool pinnedOnStartup: false
property bool hoverToReveal: true // When false, only reveals on empty workspace
property list<string> pinnedApps: [ // IDs of pinned entries
"org.kde.dolphin", "kitty",]
property list<string> ignoredAppRegexes: []
}
property JsonObject language: JsonObject {
property JsonObject translator: JsonObject {
property string engine: "auto" // Run `trans -list-engines` for available engines. auto should use google
property string targetLanguage: "auto" // Run `trans -list-all` for available languages
property string sourceLanguage: "auto"
}
}
property JsonObject networking: JsonObject {
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
property JsonObject osd: JsonObject {
property int timeout: 1000
}
property JsonObject osk: JsonObject {
property string layout: "qwerty_full"
property bool pinnedOnStartup: false
}
property JsonObject overview: JsonObject {
property real scale: 0.18 // Relative to screen size
property real rows: 2
property real columns: 5
}
property JsonObject resources: JsonObject {
property int updateInterval: 3000
}
property JsonObject search: JsonObject {
property int nonAppResultDelay: 30 // This prevents lagging when typing
property string engineBaseUrl: "https://www.google.com/search?q="
property list<string> excludedSites: ["quora.com"]
property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird.
property JsonObject prefix: JsonObject {
property string action: "/"
property string clipboard: ";"
property string emojis: ":"
}
}
property JsonObject sidebar: JsonObject {
property JsonObject translator: JsonObject {
property int delay: 300 // Delay before sending request. Reduces (potential) rate limits and lag.
}
property JsonObject booru: JsonObject {
property bool allowNsfw: false
property string defaultProvider: "yandere"
property int limit: 20
property JsonObject zerochan: JsonObject {
property string username: "[unset]"
}
}
}
property JsonObject time: JsonObject {
// https://doc.qt.io/qt-6/qtime.html#toString
property string format: "hh:mm"
property string dateFormat: "ddd, dd/MM"
}
property JsonObject windows: JsonObject {
property bool showTitlebar: true // Client-side decoration for shell apps
property bool centerTitle: true
}
property JsonObject hacks: JsonObject {
property int arbitraryRaceConditionDelay: 20 // milliseconds
}
property JsonObject screenshotTool: JsonObject {
property bool showContentRegions: true
}
}
}
}
@@ -1,49 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property alias states: persistentStatesJsonAdapter
property string fileDir: Directories.state
property string fileName: "states.json"
property string filePath: `${root.fileDir}/${root.fileName}`
FileView {
path: root.filePath
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: {
writeAdapter()
}
onLoadFailed: error => {
console.log("Failed to load persistent states file:", error);
if (error == FileViewError.FileNotFound) {
writeAdapter();
}
}
adapter: JsonAdapter {
id: persistentStatesJsonAdapter
property JsonObject ai: JsonObject {
property string model
property real temperature: 0.5
}
property JsonObject sidebar: JsonObject {
property JsonObject bottomGroup: JsonObject {
property bool collapsed: false
property int tab: 0
}
}
property JsonObject booru: JsonObject {
property bool allowNsfw: false
property string provider: "yandere"
}
}
}
}
@@ -1,114 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
id: root
/**
* Returns a color with the hue of color2 and the saturation, value, and alpha of color1.
*
* @param {string} color1 - The base color (any Qt.color-compatible string).
* @param {string} color2 - The color to take hue from.
* @returns {Qt.rgba} The resulting color.
*/
function colorWithHueOf(color1, color2) {
var c1 = Qt.color(color1);
var c2 = Qt.color(color2);
// Qt.color hsvHue/hsvSaturation/hsvValue/alpha return 0-1
var hue = c2.hsvHue;
var sat = c1.hsvSaturation;
var val = c1.hsvValue;
var alpha = c1.a;
return Qt.hsva(hue, sat, val, alpha);
}
/**
* Returns a color with the saturation of color2 and the hue/value/alpha of color1.
*
* @param {string} color1 - The base color (any Qt.color-compatible string).
* @param {string} color2 - The color to take saturation from.
* @returns {Qt.rgba} The resulting color.
*/
function colorWithSaturationOf(color1, color2) {
var c1 = Qt.color(color1);
var c2 = Qt.color(color2);
var hue = c1.hsvHue;
var sat = c2.hsvSaturation;
var val = c1.hsvValue;
var alpha = c1.a;
return Qt.hsva(hue, sat, val, alpha);
}
/**
* Returns a color with the given lightness and the hue, saturation, and alpha of the input color (using HSL).
*
* @param {string} color - The base color (any Qt.color-compatible string).
* @param {number} lightness - The lightness value to use (0-1).
* @returns {Qt.rgba} The resulting color.
*/
function colorWithLightness(color, lightness) {
var c = Qt.color(color);
return Qt.hsla(c.hslHue, c.hslSaturation, lightness, c.a);
}
/**
* Returns a color with the lightness of color2 and the hue, saturation, and alpha of color1 (using HSL).
*
* @param {string} color1 - The base color (any Qt.color-compatible string).
* @param {string} color2 - The color to take lightness from.
* @returns {Qt.rgba} The resulting color.
*/
function colorWithLightnessOf(color1, color2) {
var c2 = Qt.color(color2);
return colorWithLightness(color1, c2.hslLightness);
}
/**
* Adapts color1 to the accent (hue and saturation) of color2 using HSL, keeping lightness and alpha from color1.
*
* @param {string} color1 - The base color (any Qt.color-compatible string).
* @param {string} color2 - The accent color.
* @returns {Qt.rgba} The resulting color.
*/
function adaptToAccent(color1, color2) {
var c1 = Qt.color(color1);
var c2 = Qt.color(color2);
var hue = c2.hslHue;
var sat = c2.hslSaturation;
var light = c1.hslLightness;
var alpha = c1.a;
return Qt.hsla(hue, sat, light, alpha);
}
/**
* Mixes two colors by a given percentage.
*
* @param {string} color1 - The first color (any Qt.color-compatible string).
* @param {string} color2 - The second color.
* @param {number} percentage - The mix ratio (0-1). 1 = all color1, 0 = all color2.
* @returns {Qt.rgba} The resulting mixed color.
*/
function mix(color1, color2, percentage = 0.5) {
var c1 = Qt.color(color1);
var c2 = Qt.color(color2);
return Qt.rgba(percentage * c1.r + (1 - percentage) * c2.r, percentage * c1.g + (1 - percentage) * c2.g, percentage * c1.b + (1 - percentage) * c2.b, percentage * c1.a + (1 - percentage) * c2.a);
}
/**
* Transparentizes a color by a given percentage.
*
* @param {string} color - The color (any Qt.color-compatible string).
* @param {number} percentage - The amount to transparentize (0-1).
* @returns {Qt.rgba} The resulting color.
*/
function transparentize(color, percentage = 1) {
var c = Qt.color(color);
return Qt.rgba(c.r, c.g, c.b, c.a * (1 - percentage));
}
}
@@ -1,41 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
id: root
/**
* Trims the File protocol off the input string
* @param {string} str
* @returns {string}
*/
function trimFileProtocol(str) {
return str.startsWith("file://") ? str.slice(7) : str;
}
/**
* Extracts the file name from a file path
* @param {string} str
* @returns {string}
*/
function fileNameForPath(str) {
if (typeof str !== "string") return "";
const trimmed = trimFileProtocol(str);
return trimmed.split(/[\\/]/).pop();
}
/**
* Removes the file extension from a file path or name
* @param {string} str
* @returns {string}
*/
function trimFileExt(str) {
if (typeof str !== "string") return "";
const trimmed = trimFileProtocol(str);
const lastDot = trimmed.lastIndexOf(".");
if (lastDot > -1 && lastDot > trimmed.lastIndexOf("/")) {
return trimmed.slice(0, lastDot);
}
return trimmed;
}
}
@@ -1,221 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
id: root
/**
* Formats a string according to the args that are passed inc
* @param { string } str
* @param {...any} args
* @returns
*/
function format(str, ...args) {
return str.replace(/{(\d+)}/g, (match, index) => typeof args[index] !== 'undefined' ? args[index] : match);
}
/**
* Returns the domain of the passed in url or null
* @param { string } url
* @returns { string| null }
*/
function getDomain(url) {
const match = url.match(/^(?:https?:\/\/)?(?:www\.)?([^\/]+)/);
return match ? match[1] : null;
}
/**
* Returns the base url of the passed in url or null
* @param { string } url
* @returns { string | null }
*/
function getBaseUrl(url) {
const match = url.match(/^(https?:\/\/[^\/]+)(\/.*)?$/);
return match ? match[1] : null;
}
/**
* Escapes single quotes in shell commands
* @param { string } str
* @returns { string }
*/
function shellSingleQuoteEscape(str) {
// escape single quotes
return String(str)
// .replace(/\\/g, '\\\\')
.replace(/'/g, "'\\''");
}
/**
* Splits markdown blocks into three different types: text, think, and code.
* @param { string } markdown
*/
function splitMarkdownBlocks(markdown) {
const regex = /```(\w+)?\n([\s\S]*?)```|<think>([\s\S]*?)<\/think>/g;
/**
* @type {{type: "text" | "think" | "code"; content: string; lang: string | undefined; completed: boolean | undefined}[]}
*/
let result = [];
let lastIndex = 0;
let match;
while ((match = regex.exec(markdown)) !== null) {
if (match.index > lastIndex) {
const text = markdown.slice(lastIndex, match.index);
if (text.trim()) {
result.push({
type: "text",
content: text
});
}
}
if (match[0].startsWith('```')) {
if (match[2] && match[2].trim()) {
result.push({
type: "code",
lang: match[1] || "",
content: match[2],
completed: true
});
}
} else if (match[0].startsWith('<think>')) {
if (match[3] && match[3].trim()) {
result.push({
type: "think",
content: match[3],
completed: true
});
}
}
lastIndex = regex.lastIndex;
}
// Handle any remaining text after the last match
if (lastIndex < markdown.length) {
const text = markdown.slice(lastIndex);
// Check for unfinished <think> block
const thinkStart = text.indexOf('<think>');
const codeStart = text.indexOf('```');
if (thinkStart !== -1 && (codeStart === -1 || thinkStart < codeStart)) {
const beforeThink = text.slice(0, thinkStart);
if (beforeThink.trim()) {
result.push({
type: "text",
content: beforeThink
});
}
const thinkContent = text.slice(thinkStart + 7);
if (thinkContent.trim()) {
result.push({
type: "think",
content: thinkContent,
completed: false
});
}
} else if (codeStart !== -1) {
const beforeCode = text.slice(0, codeStart);
if (beforeCode.trim()) {
result.push({
type: "text",
content: beforeCode
});
}
// Try to detect language after ```
const codeLangMatch = text.slice(codeStart + 3).match(/^(\w+)?\n/);
let lang = "";
let codeContentStart = codeStart + 3;
if (codeLangMatch) {
lang = codeLangMatch[1] || "";
codeContentStart += codeLangMatch[0].length;
} else if (text[codeStart + 3] === '\n') {
codeContentStart += 1;
}
const codeContent = text.slice(codeContentStart);
if (codeContent.trim()) {
result.push({
type: "code",
lang,
content: codeContent,
completed: false
});
}
} else if (text.trim()) {
result.push({
type: "text",
content: text
});
}
}
// console.log(JSON.stringify(result, null, 2));
return result;
}
/**
* Returns the original string with backslashes escaped
* @param { string } str
* @returns { string }
*/
function escapeBackslashes(str) {
return str.replace(/\\/g, '\\\\');
}
/**
* Wraps words to supplied maximum length
* @param { string | null } str
* @param { number } maxLen
* @returns { string }
*/
function wordWrap(str, maxLen) {
if (!str)
return "";
let words = str.split(" ");
let lines = [];
let current = "";
for (let i = 0; i < words.length; ++i) {
if ((current + (current.length > 0 ? " " : "") + words[i]).length > maxLen) {
if (current.length > 0)
lines.push(current);
current = words[i];
} else {
current += (current.length > 0 ? " " : "") + words[i];
}
}
if (current.length > 0)
lines.push(current);
return lines.join("\n");
}
function cleanMusicTitle(title) {
if (!title)
return "";
// Brackets
title = title.replace(/^ *\([^)]*\) */g, " "); // Round brackets
title = title.replace(/^ *\[[^\]]*\] */g, " "); // Square brackets
title = title.replace(/^ *\{[^\}]*\} */g, " "); // Curly brackets
// Japenis brackets
title = title.replace(/^ *【[^】]*】/, ""); // Touhou
title = title.replace(/^ *《[^》]*》/, ""); // ??
title = title.replace(/^ *「[^」]*」/, ""); // OP/ED thingie
title = title.replace(/^ *『[^』]*』/, ""); // OP/ED thingie
return title.trim();
}
function friendlyTimeForSeconds(seconds) {
if (isNaN(seconds) || seconds < 0)
return "0:00";
seconds = Math.floor(seconds);
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;
if (h > 0) {
return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
} else {
return `${m}:${s.toString().padStart(2, '0')}`;
}
}
function escapeHtml(str) {
if (typeof str !== 'string')
return str;
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}
}
@@ -1,95 +0,0 @@
// From https://github.com/rafzby/circular-progressbar with modifications
// License: LGPL-3.0 - A copy can be found in `licenses` folder of repo
import QtQuick
import qs.modules.common
/**
* Material 3 circular progress. See https://m3.material.io/components/progress-indicators/specs
*/
Item {
id: root
property int size: 30
property int lineWidth: 2
property real value: 0
property color primaryColor: Appearance.m3colors.m3onSecondaryContainer
property color secondaryColor: Appearance.colors.colSecondaryContainer
property real gapAngle: Math.PI / 9
property bool fill: false
property int fillOverflow: 2
property int animationDuration: 1000
property var easingType: Easing.OutCubic
width: size
height: size
signal animationFinished();
onValueChanged: {
canvas.degree = value * 360;
}
onPrimaryColorChanged: {
canvas.requestPaint();
}
onSecondaryColorChanged: {
canvas.requestPaint();
}
Canvas {
id: canvas
property real degree: 0
anchors.fill: parent
antialiasing: true
onDegreeChanged: {
requestPaint();
}
onPaint: {
var ctx = getContext("2d");
var x = root.width / 2;
var y = root.height / 2;
var radius = root.size / 2 - root.lineWidth;
var startAngle = (Math.PI / 180) * 270;
var fullAngle = (Math.PI / 180) * (270 + 360);
var progressAngle = (Math.PI / 180) * (270 + degree);
var epsilon = 0.01; // Small angle in radians
ctx.reset();
if (root.fill) {
ctx.fillStyle = root.secondaryColor;
ctx.beginPath();
ctx.arc(x, y, radius + fillOverflow, startAngle, fullAngle);
ctx.fill();
}
ctx.lineCap = 'round';
ctx.lineWidth = root.lineWidth;
// Secondary
ctx.beginPath();
ctx.arc(x, y, radius, progressAngle + gapAngle, fullAngle - gapAngle);
ctx.strokeStyle = root.secondaryColor;
ctx.stroke();
// Primary (value indication)
var endAngle = progressAngle + (value > 0 ? 0 : epsilon);
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.strokeStyle = root.primaryColor;
ctx.stroke();
}
Behavior on degree {
NumberAnimation {
duration: root.animationDuration
easing.type: root.easingType
}
}
}
}
@@ -1,96 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import qs.modules.common.functions
import Qt5Compat.GraphicalEffects
import QtQuick
import Quickshell
import Quickshell.Io
Rectangle {
id: root
property string entry
property real maxWidth
property real maxHeight
property string imageDecodePath: Directories.cliphistDecode
property string imageDecodeFileName: `${entryNumber}`
property string imageDecodeFilePath: `${imageDecodePath}/${imageDecodeFileName}`
property string source
property int entryNumber: {
if (!root.entry) return 0
const match = root.entry.match(/^(\d+)\t/)
return match ? parseInt(match[1]) : 0
}
property int imageWidth: {
if (!root.entry) return 0
const match = root.entry.match(/(\d+)x(\d+)/)
return match ? parseInt(match[1]) : 0
}
property int imageHeight: {
if (!root.entry) return 0
const match = root.entry.match(/(\d+)x(\d+)/)
return match ? parseInt(match[2]) : 0
}
property real scale: {
return Math.min(
root.maxWidth / imageWidth,
root.maxHeight / imageHeight,
1
)
}
color: Appearance.colors.colLayer1
radius: Appearance.rounding.small
implicitHeight: imageHeight * scale
implicitWidth: imageWidth * scale
Component.onCompleted: {
decodeImageProcess.running = true
}
Process {
id: decodeImageProcess
command: ["bash", "-c",
`[ -f ${imageDecodeFilePath} ] || echo '${StringUtils.shellSingleQuoteEscape(root.entry)}' | cliphist decode > '${imageDecodeFilePath}'`
]
onExited: (exitCode, exitStatus) => {
if (exitCode === 0) {
root.source = imageDecodeFilePath
} else {
console.error("[CliphistImage] Failed to decode image for entry:", root.entry)
root.source = ""
}
}
}
Component.onDestruction: {
Quickshell.execDetached(["bash", "-c", `[ -f '${imageDecodeFilePath}' ] && rm -f '${imageDecodeFilePath}'`])
}
Image {
id: image
anchors.fill: parent
source: Qt.resolvedUrl(root.source)
fillMode: Image.PreserveAspectFit
antialiasing: true
asynchronous: true
width: root.imageWidth * root.scale
height: root.imageHeight * root.scale
sourceSize.width: width
sourceSize.height: height
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: image.width
height: image.height
radius: root.radius
}
}
}
}
@@ -1,23 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.widgets
ColumnLayout {
id: root
property string title
default property alias data: sectionContent.data
Layout.fillWidth: true
spacing: 8
StyledText {
text: root.title
font.pixelSize: Appearance.font.pixelSize.larger
font.weight: Font.Medium
}
ColumnLayout {
id: sectionContent
spacing: 8
}
}
@@ -1,32 +0,0 @@
import qs.modules.common
import QtQuick
Text {
id: root
property real iconSize: Appearance?.font.pixelSize.small ?? 16
property real fill: 0
property real truncatedFill: Math.round(fill * 100) / 100 // Reduce memory consumption spikes from constant font remapping
renderType: Text.NativeRendering
font {
hintingPreference: Font.PreferFullHinting
family: Appearance?.font.family.iconMaterial ?? "Material Symbols Rounded"
pixelSize: iconSize
weight: Font.Normal + (Font.DemiBold - Font.Normal) * fill
variableAxes: {
"FILL": truncatedFill,
// "wght": font.weight,
// "GRAD": 0,
"opsz": iconSize,
}
}
verticalAlignment: Text.AlignVCenter
color: Appearance.m3colors.m3onBackground
// Behavior on fill {
// NumberAnimation {
// duration: Appearance?.animation.elementMoveFast.duration ?? 200
// easing.type: Appearance?.animation.elementMoveFast.type ?? Easing.BezierSpline
// easing.bezierCurve: Appearance?.animation.elementMoveFast.bezierCurve ?? [0.34, 0.80, 0.34, 1.00, 1, 1]
// }
// }
}
@@ -1,97 +0,0 @@
import qs.modules.common
import qs
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ColumnLayout {
id: root
spacing: 0
required property var tabButtonList // Something like [{"icon": "notifications", "name": Translation.tr("Notifications")}, {"icon": "volume_up", "name": Translation.tr("Volume mixer")}]
required property var externalTrackedTab
property bool enableIndicatorAnimation: false
property color colIndicator: Appearance?.colors.colPrimary ?? "#65558F"
property color colBorder: Appearance?.m3colors.m3outlineVariant ?? "#C6C6D0"
signal currentIndexChanged(int index)
property bool centerTabBar: parent.width > 500
Layout.fillWidth: !centerTabBar
Layout.alignment: Qt.AlignHCenter
implicitWidth: Math.max(tabBar.implicitWidth, 600)
TabBar {
id: tabBar
Layout.fillWidth: true
currentIndex: root.externalTrackedTab
onCurrentIndexChanged: {
root.onCurrentIndexChanged(currentIndex)
}
background: Item {
WheelHandler {
onWheel: (event) => {
if (event.angleDelta.y < 0)
tabBar.currentIndex = Math.min(tabBar.currentIndex + 1, root.tabButtonList.length - 1)
else if (event.angleDelta.y > 0)
tabBar.currentIndex = Math.max(tabBar.currentIndex - 1, 0)
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
}
Repeater {
model: root.tabButtonList
delegate: PrimaryTabButton {
selected: (index == root.externalTrackedTab)
buttonText: modelData.name
buttonIcon: modelData.icon
minimumWidth: 160
}
}
}
Item { // Tab indicator
id: tabIndicator
Layout.fillWidth: true
height: 3
Connections {
target: root
function onExternalTrackedTabChanged() {
root.enableIndicatorAnimation = true
}
}
Rectangle {
id: indicator
property int tabCount: root.tabButtonList.length
property real fullTabSize: root.width / tabCount;
property real targetWidth: tabBar.contentItem?.children[0]?.children[tabBar.currentIndex]?.tabContentWidth ?? 0
implicitWidth: targetWidth
anchors {
top: parent.top
bottom: parent.bottom
}
x: tabBar.currentIndex * fullTabSize + (fullTabSize - targetWidth) / 2
color: root.colIndicator
radius: Appearance?.rounding.full ?? 9999
Behavior on x {
animation: Appearance?.animation.elementMove.numberAnimation.createObject(this)
}
Behavior on implicitWidth {
animation: Appearance?.animation.elementMove.numberAnimation.createObject(this)
}
}
}
Rectangle { // Tabbar bottom border
id: tabBarBottomBorder
Layout.fillWidth: true
implicitHeight: 1
color: root.colBorder
}
}
@@ -1,171 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
TabButton {
id: button
property string buttonText
property string buttonIcon
property real minimumWidth: 110
property bool selected: false
property int tabContentWidth: contentItem.children[0].implicitWidth
property int rippleDuration: 1200
height: buttonBackground.height
implicitWidth: Math.max(tabContentWidth, buttonBackground.implicitWidth, minimumWidth)
property color colBackground: ColorUtils.transparentize(Appearance?.colors.colLayer1Hover, 1) || "transparent"
property color colBackgroundHover: Appearance?.colors.colLayer1Hover ?? "#E5DFED"
property color colRipple: Appearance?.colors.colLayer1Active ?? "#D6CEE2"
property color colActive: Appearance?.colors.colPrimary ?? "#65558F"
property color colInactive: Appearance?.colors.colOnLayer1 ?? "#45464F"
component RippleAnim: NumberAnimation {
duration: rippleDuration
easing.type: Appearance?.animation.elementMoveEnter.type
easing.bezierCurve: Appearance?.animationCurves.standardDecel
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onPressed: (event) => {
const {x,y} = event
const stateY = buttonBackground.y;
rippleAnim.x = x;
rippleAnim.y = y - stateY;
const dist = (ox,oy) => ox*ox + oy*oy
const stateEndY = stateY + buttonBackground.height
rippleAnim.radius = Math.sqrt(Math.max(dist(0, stateY), dist(0, stateEndY), dist(width, stateY), dist(width, stateEndY)))
rippleFadeAnim.complete();
rippleAnim.restart();
}
onReleased: (event) => {
button.click() // Because the MouseArea already consumed the event
rippleFadeAnim.restart();
}
}
RippleAnim {
id: rippleFadeAnim
target: ripple
property: "opacity"
to: 0
}
SequentialAnimation {
id: rippleAnim
property real x
property real y
property real radius
PropertyAction {
target: ripple
property: "x"
value: rippleAnim.x
}
PropertyAction {
target: ripple
property: "y"
value: rippleAnim.y
}
PropertyAction {
target: ripple
property: "opacity"
value: 1
}
ParallelAnimation {
RippleAnim {
target: ripple
properties: "implicitWidth,implicitHeight"
from: 0
to: rippleAnim.radius * 2
}
}
}
background: Rectangle {
id: buttonBackground
radius: Appearance?.rounding.small
implicitHeight: 50
color: (button.hovered ? button.colBackgroundHover : button.colBackground)
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: buttonBackground.width
height: buttonBackground.height
radius: buttonBackground.radius
}
}
Behavior on color {
animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
}
Item {
id: ripple
width: ripple.implicitWidth
height: ripple.implicitHeight
opacity: 0
property real implicitWidth: 0
property real implicitHeight: 0
visible: width > 0 && height > 0
Behavior on opacity {
animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
}
RadialGradient {
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 0.0; color: button.colRipple }
GradientStop { position: 0.3; color: button.colRipple }
GradientStop { position: 0.5 ; color: Qt.rgba(button.colRipple.r, button.colRipple.g, button.colRipple.b, 0) }
}
}
transform: Translate {
x: -ripple.width / 2
y: -ripple.height / 2
}
}
}
contentItem: Item {
anchors.centerIn: buttonBackground
ColumnLayout {
anchors.centerIn: parent
spacing: 0
MaterialSymbol {
visible: buttonIcon?.length > 0
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
text: buttonIcon
iconSize: Appearance?.font.pixelSize.hugeass ?? 25
fill: selected ? 1 : 0
color: selected ? button.colActive : button.colInactive
Behavior on color {
animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
}
}
StyledText {
id: buttonTextWidget
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Appearance?.font.pixelSize.small
color: selected ? button.colActive : button.colInactive
text: buttonText
Behavior on color {
animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
}
}
}
}
}
@@ -1,61 +0,0 @@
import QtQuick 2.9
Item {
id: root
enum CornerEnum { TopLeft, TopRight, BottomLeft, BottomRight }
property var corner: RoundCorner.CornerEnum.TopLeft // Default to TopLeft
property int size: 25
property color color: "#000000"
onColorChanged: {
canvas.requestPaint();
}
onCornerChanged: {
canvas.requestPaint();
}
implicitWidth: size
implicitHeight: size
Canvas {
id: canvas
anchors.fill: parent
antialiasing: true
onPaint: {
var ctx = getContext("2d");
var r = root.size;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
switch (root.corner) {
case RoundCorner.CornerEnum.TopLeft:
ctx.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
ctx.lineTo(0, 0);
break;
case RoundCorner.CornerEnum.TopRight:
ctx.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
ctx.lineTo(r, 0);
break;
case RoundCorner.CornerEnum.BottomLeft:
ctx.arc(r, 0, r, Math.PI / 2, Math.PI);
ctx.lineTo(0, r);
break;
case RoundCorner.CornerEnum.BottomRight:
ctx.arc(0, 0, r, 0, Math.PI / 2);
ctx.lineTo(r, r);
break;
}
ctx.closePath();
ctx.fillStyle = root.color;
ctx.fill();
}
}
Behavior on size {
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
}
}
@@ -1,24 +0,0 @@
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import qs.services
import qs.modules.common
import qs.modules.common.widgets
GroupButton {
id: root
horizontalPadding: 12
verticalPadding: 8
bounce: false
property bool leftmost: false
property bool rightmost: false
leftRadius: (toggled || leftmost) ? (height / 2) : Appearance.rounding.unsharpenmore
rightRadius: (toggled || rightmost) ? (height / 2) : Appearance.rounding.unsharpenmore
colBackground: Appearance.colors.colSecondaryContainer
contentItem: StyledText {
color: parent.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer
text: root.buttonText
}
}
@@ -1,105 +0,0 @@
import qs
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import QtQuick
/**
* A ListView with animations.
*/
ListView {
id: root
spacing: 5
property real removeOvershoot: 20 // Account for gaps and bouncy animations
property int dragIndex: -1
property real dragDistance: 0
property bool popin: true
function resetDrag() {
root.dragIndex = -1
root.dragDistance = 0
}
add: Transition {
animations: [
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: popin ? "opacity,scale" : "opacity",
from: 0,
to: 1,
}),
]
}
addDisplaced: Transition {
animations: [
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y",
}),
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: popin ? "opacity,scale" : "opacity",
to: 1,
}),
]
}
// displaced: Transition {
// animations: [
// Appearance?.animation.elementMove.numberAnimation.createObject(this, {
// property: "y",
// }),
// Appearance?.animation.elementMove.numberAnimation.createObject(this, {
// properties: "opacity,scale",
// to: 1,
// }),
// ]
// }
// move: Transition {
// animations: [
// Appearance?.animation.elementMove.numberAnimation.createObject(this, {
// property: "y",
// }),
// Appearance?.animation.elementMove.numberAnimation.createObject(this, {
// properties: "opacity,scale",
// to: 1,
// }),
// ]
// }
// moveDisplaced: Transition {
// animations: [
// Appearance?.animation.elementMove.numberAnimation.createObject(this, {
// property: "y",
// }),
// Appearance?.animation.elementMove.numberAnimation.createObject(this, {
// properties: "opacity,scale",
// to: 1,
// }),
// ]
// }
remove: Transition {
animations: [
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "x",
to: root.width + root.removeOvershoot,
}),
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "opacity",
to: 0,
})
]
}
// This is movement when something is removed, not removing animation!
removeDisplaced: Transition {
animations: [
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y",
}),
Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale",
to: 1,
}),
]
}
}
@@ -1,103 +0,0 @@
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import Qt5Compat.GraphicalEffects
/**
* Material 3 progress bar. See https://m3.material.io/components/progress-indicators/overview
*/
ProgressBar {
id: root
property real valueBarWidth: 120
property real valueBarHeight: 4
property real valueBarGap: 4
property color highlightColor: Appearance?.colors.colPrimary ?? "#685496"
property color trackColor: Appearance?.m3colors.m3secondaryContainer ?? "#F1D3F9"
property bool sperm: false // If true, the progress bar will have a wavy fill effect
property bool animateSperm: true
property real spermAmplitudeMultiplier: sperm ? 0.5 : 0
property real spermFrequency: 6
property real spermFps: 60
Behavior on spermAmplitudeMultiplier {
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on value {
animation: Appearance?.animation.elementMoveEnter.numberAnimation.createObject(this)
}
background: Item {
anchors.fill: parent
implicitHeight: valueBarHeight
implicitWidth: valueBarWidth
}
contentItem: Item {
anchors.fill: parent
Canvas {
id: wavyFill
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
}
height: parent.height * 6
onPaint: {
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
var progress = root.visualPosition;
var fillWidth = progress * width;
var amplitude = parent.height * root.spermAmplitudeMultiplier;
var frequency = root.spermFrequency;
var phase = Date.now() / 400.0;
var centerY = height / 2;
ctx.strokeStyle = root.highlightColor;
ctx.lineWidth = parent.height;
ctx.lineCap = "round";
ctx.beginPath();
for (var x = ctx.lineWidth / 2; x <= fillWidth; x += 1) {
var waveY = centerY + amplitude * Math.sin(frequency * 2 * Math.PI * x / width + phase);
if (x === 0)
ctx.moveTo(x, waveY);
else
ctx.lineTo(x, waveY);
}
ctx.stroke();
}
Connections {
target: root
function onValueChanged() { wavyFill.requestPaint(); }
function onHighlightColorChanged() { wavyFill.requestPaint(); }
}
Timer {
interval: 1000 / root.spermFps
running: root.animateSperm
repeat: root.sperm
onTriggered: wavyFill.requestPaint()
}
}
Rectangle { // Right remaining part fill
anchors.right: parent.right
width: (1 - root.visualPosition) * parent.width - valueBarGap
height: parent.height
radius: Appearance?.rounding.full ?? 9999
color: root.trackColor
}
Rectangle { // Stop point
anchors.right: parent.right
width: valueBarGap
height: valueBarGap
radius: Appearance?.rounding.full ?? 9999
color: root.highlightColor
}
}
}
@@ -1,15 +0,0 @@
import qs.modules.common
import QtQuick
import QtQuick.Layouts
Text {
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
font {
hintingPreference: Font.PreferFullHinting
family: Appearance?.font.family.main ?? "sans-serif"
pixelSize: Appearance?.font.pixelSize.small ?? 15
}
color: Appearance?.m3colors.m3onBackground ?? "black"
linkColor: Appearance?.m3colors.m3primary
}
@@ -1,60 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ToolTip {
id: root
property string content
property bool extraVisibleCondition: true
property bool alternativeVisibleCondition: false
property bool internalVisibleCondition: {
const ans = (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition
return ans
}
verticalPadding: 5
horizontalPadding: 10
opacity: internalVisibleCondition ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
}
background: null
contentItem: Item {
id: contentItemBackground
implicitWidth: tooltipTextObject.width + 2 * root.horizontalPadding
implicitHeight: tooltipTextObject.height + 2 * root.verticalPadding
Rectangle {
id: backgroundRectangle
anchors.bottom: contentItemBackground.bottom
anchors.horizontalCenter: contentItemBackground.horizontalCenter
color: Appearance?.colors.colTooltip ?? "#3C4043"
radius: Appearance?.rounding.verysmall ?? 7
width: internalVisibleCondition ? (tooltipTextObject.width + 2 * padding) : 0
height: internalVisibleCondition ? (tooltipTextObject.height + 2 * padding) : 0
clip: true
Behavior on width {
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on height {
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
}
StyledText {
id: tooltipTextObject
anchors.centerIn: parent
text: content
font.pixelSize: Appearance?.font.pixelSize.smaller ?? 14
font.hintingPreference: Font.PreferNoHinting // Prevent shaky text
color: Appearance?.colors.colOnTooltip ?? "#FFFFFF"
wrapMode: Text.Wrap
}
}
}
}
@@ -1,99 +0,0 @@
import qs
import qs.modules.common
import qs.modules.common.functions
import qs.modules.lock
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: root
// This stores all the information shared between the lock surfaces on each screen.
// https://github.com/quickshell-mirror/quickshell-examples/tree/master/lockscreen
LockContext {
id: lockContext
onUnlocked: {
// Unlock the screen before exiting, or the compositor will display a
// fallback lock you can't interact with.
GlobalStates.screenLocked = false;
}
}
WlSessionLock {
id: lock
locked: GlobalStates.screenLocked
WlSessionLockSurface {
color: "transparent"
Loader {
active: GlobalStates.screenLocked
anchors.fill: parent
opacity: active ? 1 : 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
sourceComponent: LockSurface {
context: lockContext
}
}
}
}
// Blur layer hack
Variants {
model: Quickshell.screens
LazyLoader {
id: blurLayerLoader
required property var modelData
active: GlobalStates.screenLocked
component: PanelWindow {
screen: blurLayerLoader.modelData
WlrLayershell.namespace: "quickshell:lockWindowPusher"
color: "transparent"
anchors {
top: true
left: true
right: true
}
// implicitHeight: lockContext.currentText == "" ? 1 : screen.height
implicitHeight: 1
exclusiveZone: screen.height * 3 // For some reason if we don't multiply by some number it would look really weird
}
}
}
IpcHandler {
target: "lock"
function activate(): void {
GlobalStates.screenLocked = true;
}
function focus(): void {
lockContext.shouldReFocus();
}
}
GlobalShortcut {
name: "lock"
description: "Locks the screen"
onPressed: {
GlobalStates.screenLocked = true;
}
}
GlobalShortcut {
name: "lockFocus"
description: "Re-focuses the lock screen. This is because Hyprland after waking up for whatever reason"
+ "decides to keyboard-unfocus the lock screen"
onPressed: {
// console.log("I BEG FOR PLEAS REFOCUZ")
lockContext.shouldReFocus();
}
}
}
@@ -1,67 +0,0 @@
import qs
import QtQuick
import Quickshell
import Quickshell.Services.Pam
Scope {
id: root
signal shouldReFocus()
signal unlocked()
signal failed()
// These properties are in the context and not individual lock surfaces
// so all surfaces can share the same state.
property string currentText: ""
property bool unlockInProgress: false
property bool showFailure: false
Timer {
id: passwordClearTimer
interval: 10000
onTriggered: {
root.currentText = "";
}
}
onCurrentTextChanged: {
showFailure = false; // Clear the failure text once the user starts typing.
GlobalStates.screenLockContainsCharacters = currentText.length > 0;
passwordClearTimer.restart();
}
function tryUnlock() {
if (currentText === "") return;
root.unlockInProgress = true;
pam.start();
}
PamContext {
id: pam
// Its best to have a custom pam config for quickshell, as the system one
// might not be what your interface expects, and break in some way.
// This particular example only supports passwords.
configDirectory: "pam"
config: "password.conf"
// pam_unix will ask for a response for the password prompt
onPamMessage: {
if (this.responseRequired) {
this.respond(root.currentText);
}
}
// pam_unix won't send any important messages so all we need is the completion status.
onCompleted: result => {
if (result == PamResult.Success) {
root.unlocked();
} else {
root.showFailure = true;
}
root.currentText = "";
root.unlockInProgress = false;
}
}
}
@@ -1,147 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
MouseArea {
id: root
required property LockContext context
property bool active: false
property bool showInputField: active || context.currentText.length > 0
function forceFieldFocus() {
passwordBox.forceActiveFocus();
}
Component.onCompleted: {
forceFieldFocus();
}
Connections {
target: context
function onShouldReFocus() {
forceFieldFocus();
}
}
Keys.onPressed: (event) => { // Esc to clear
// console.log("KEY!!")
if (event.key === Qt.Key_Escape) {
root.context.currentText = ""
}
forceFieldFocus();
}
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onPressed: (mouse) => {
forceFieldFocus();
// console.log("Pressed")
}
onPositionChanged: (mouse) => {
forceFieldFocus();
// console.log(JSON.stringify(mouse))
}
anchors.fill: parent
// RippleButton {
// anchors {
// top: parent.top
// left: parent.left
// leftMargin: 10
// topMargin: 10
// }
// implicitHeight: 40
// colBackground: Appearance.colors.colLayer2
// onClicked: context.unlocked()
// contentItem: StyledText {
// text: "[[ DEBUG BYPASS ]]"
// }
// }
// Password entry
Rectangle {
id: passwordBoxContainer
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: root.showInputField ? 20 : -height
}
Behavior on anchors.bottomMargin {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
radius: Appearance.rounding.full
color: Appearance.colors.colLayer2
implicitWidth: 160
implicitHeight: 44
StyledText {
visible: root.context.showFailure && passwordBox.text.length == 0
anchors.centerIn: parent
text: "Incorrect"
color: Appearance.m3colors.m3error
}
StyledTextInput {
id: passwordBox
anchors {
fill: parent
margins: 10
}
clip: true
horizontalAlignment: TextInput.AlignHCenter
verticalAlignment: TextInput.AlignVCenter
focus: true
onFocusChanged: root.forceFieldFocus();
color: Appearance.colors.colOnLayer2
font {
pixelSize: 10
}
// Password
enabled: !root.context.unlockInProgress
echoMode: TextInput.Password
inputMethodHints: Qt.ImhSensitiveData
// Synchronizing (across monitors) and unlocking
onTextChanged: root.context.currentText = this.text
onAccepted: root.context.tryUnlock()
Connections {
target: root.context
function onCurrentTextChanged() {
passwordBox.text = root.context.currentText;
}
}
}
}
RippleButton {
anchors {
verticalCenter: passwordBoxContainer.verticalCenter
left: passwordBoxContainer.right
leftMargin: 5
}
visible: opacity > 0
implicitHeight: passwordBoxContainer.implicitHeight - 12
implicitWidth: implicitHeight
toggled: true
buttonRadius: passwordBoxContainer.radius
colBackground: Appearance.colors.colLayer2
onClicked: root.context.tryUnlock()
contentItem: MaterialSymbol {
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
iconSize: 24
text: "arrow_right_alt"
color: Appearance.colors.colOnPrimary
}
}
}
@@ -1 +0,0 @@
auth required pam_unix.so
@@ -1,153 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import Quickshell.Wayland
Scope {
id: root
property bool showOsdValues: false
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen)
function triggerOsd() {
showOsdValues = true
osdTimeout.restart()
}
Timer {
id: osdTimeout
interval: Config.options.osd.timeout
repeat: false
running: false
onTriggered: {
showOsdValues = false
}
}
Connections {
target: Audio.sink?.audio ?? null
function onVolumeChanged() {
if (!Audio.ready) return
root.showOsdValues = false
}
}
Connections {
target: Brightness
function onBrightnessChanged() {
if (!root.brightnessMonitor.ready) return
root.triggerOsd()
}
}
Loader {
id: osdLoader
active: showOsdValues
sourceComponent: PanelWindow {
id: osdRoot
Connections {
target: root
function onFocusedScreenChanged() {
osdRoot.screen = root.focusedScreen
}
}
exclusionMode: ExclusionMode.Normal
WlrLayershell.namespace: "quickshell:onScreenDisplay"
WlrLayershell.layer: WlrLayer.Overlay
color: "transparent"
anchors {
top: !Config.options.bar.bottom
bottom: Config.options.bar.bottom
}
mask: Region {
item: osdValuesWrapper
}
implicitWidth: columnLayout.implicitWidth
implicitHeight: columnLayout.implicitHeight
visible: osdLoader.active
ColumnLayout {
id: columnLayout
anchors.horizontalCenter: parent.horizontalCenter
Item {
id: osdValuesWrapper
// Extra space for shadow
implicitHeight: osdValues.implicitHeight + Appearance.sizes.elevationMargin * 2
implicitWidth: osdValues.implicitWidth
clip: true
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: root.showOsdValues = false
}
Behavior on implicitHeight {
NumberAnimation {
duration: Appearance.animation.menuDecel.duration
easing.type: Appearance.animation.menuDecel.type
}
}
OsdValueIndicator {
id: osdValues
anchors.fill: parent
anchors.margins: Appearance.sizes.elevationMargin
value: root.brightnessMonitor?.brightness ?? 50
icon: "light_mode"
rotateIcon: true
scaleIcon: true
name: Translation.tr("Brightness")
}
}
}
}
}
IpcHandler {
target: "osdBrightness"
function trigger() {
root.triggerOsd()
}
function hide() {
showOsdValues = false
}
function toggle() {
showOsdValues = !showOsdValues
}
}
GlobalShortcut {
name: "osdBrightnessTrigger"
description: "Triggers brightness OSD on press"
onPressed: {
root.triggerOsd()
}
}
GlobalShortcut {
name: "osdBrightnessHide"
description: "Hides brightness OSD on press"
onPressed: {
root.showOsdValues = false
}
}
}
@@ -1,114 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
Item { // Window
id: root
property var toplevel
property var windowData
property var monitorData
property var scale
property var availableWorkspaceWidth
property var availableWorkspaceHeight
property bool restrictToWorkspace: true
property real initX: Math.max((windowData?.at[0] - (monitorData?.x ?? 0) - monitorData?.reserved[0]) * root.scale, 0) + xOffset
property real initY: Math.max((windowData?.at[1] - (monitorData?.y ?? 0) - monitorData?.reserved[1]) * root.scale, 0) + yOffset
property real xOffset: 0
property real yOffset: 0
property var targetWindowWidth: windowData?.size[0] * scale
property var targetWindowHeight: windowData?.size[1] * scale
property bool hovered: false
property bool pressed: false
property var iconToWindowRatio: 0.35
property var xwaylandIndicatorToIconRatio: 0.35
property var iconToWindowRatioCompact: 0.6
property var iconPath: Quickshell.iconPath(AppSearch.guessIcon(windowData?.class), "image-missing")
property bool compactMode: Appearance.font.pixelSize.smaller * 4 > targetWindowHeight || Appearance.font.pixelSize.smaller * 4 > targetWindowWidth
property bool indicateXWayland: windowData?.xwayland ?? false
x: initX
y: initY
width: windowData?.size[0] * root.scale
height: windowData?.size[1] * root.scale
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: root.width
height: root.height
radius: Appearance.rounding.windowRounding * root.scale
}
}
Behavior on x {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
Behavior on y {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
Behavior on width {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
Behavior on height {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
ScreencopyView {
id: windowPreview
anchors.fill: parent
captureSource: GlobalStates.overviewOpen ? root.toplevel : null
live: true
Rectangle {
anchors.fill: parent
radius: Appearance.rounding.windowRounding * root.scale
color: pressed ? ColorUtils.transparentize(Appearance.colors.colLayer2Active, 0.5) :
hovered ? ColorUtils.transparentize(Appearance.colors.colLayer2Hover, 0.7) :
ColorUtils.transparentize(Appearance.colors.colLayer2)
border.color : ColorUtils.transparentize(Appearance.m3colors.m3outline, 0.7)
border.width : 1
}
ColumnLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
spacing: Appearance.font.pixelSize.smaller * 0.5
Image {
id: windowIcon
property var iconSize: {
// console.log("-=-=-", root.toplevel.title, "-=-=-")
// console.log("Target window size:", targetWindowWidth, targetWindowHeight)
// console.log("Icon ratio:", root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio)
// console.log("Scale:", root.monitorData.scale)
// console.log("Final:", Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale)
return Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / root.monitorData.scale;
}
// mipmap: true
Layout.alignment: Qt.AlignHCenter
source: root.iconPath
width: iconSize
height: iconSize
sourceSize: Qt.size(iconSize, iconSize)
Behavior on width {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
Behavior on height {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
}
}
}
}
@@ -1,66 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: screenCorners
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
component CornerPanelWindow: PanelWindow {
id: cornerPanelWindow
visible: (Config.options.appearance.fakeScreenRounding === 1 || (Config.options.appearance.fakeScreenRounding === 2 && !activeWindow?.fullscreen))
property var corner
exclusionMode: ExclusionMode.Ignore
mask: Region {
item: null
}
WlrLayershell.namespace: "quickshell:screenCorners"
WlrLayershell.layer: WlrLayer.Overlay
color: "transparent"
anchors {
top: cornerPanelWindow.corner === RoundCorner.CornerEnum.TopLeft || cornerPanelWindow.corner === RoundCorner.CornerEnum.TopRight
left: cornerPanelWindow.corner === RoundCorner.CornerEnum.TopLeft || cornerPanelWindow.corner === RoundCorner.CornerEnum.BottomLeft
bottom: cornerPanelWindow.corner === RoundCorner.CornerEnum.BottomLeft || cornerPanelWindow.corner === RoundCorner.CornerEnum.BottomRight
right: cornerPanelWindow.corner === RoundCorner.CornerEnum.TopRight || cornerPanelWindow.corner === RoundCorner.CornerEnum.BottomRight
}
implicitWidth: cornerWidget.implicitWidth
implicitHeight: cornerWidget.implicitHeight
RoundCorner {
id: cornerWidget
size: Appearance.rounding.screenRounding
corner: cornerPanelWindow.corner
}
}
Variants {
model: Quickshell.screens
Scope {
required property var modelData
CornerPanelWindow {
screen: modelData
corner: RoundCorner.CornerEnum.TopLeft
}
CornerPanelWindow {
screen: modelData
corner: RoundCorner.CornerEnum.TopRight
}
CornerPanelWindow {
screen: modelData
corner: RoundCorner.CornerEnum.BottomLeft
}
CornerPanelWindow {
screen: modelData
corner: RoundCorner.CornerEnum.BottomRight
}
}
}
}
@@ -1,45 +0,0 @@
import QtQuick
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Color generation")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Shell & utilities")
checked: Config.options.appearance.wallpaperTheming.enableAppsAndShell
onCheckedChanged: {
Config.options.appearance.wallpaperTheming.enableAppsAndShell = checked;
}
}
ConfigSwitch {
text: Translation.tr("Qt apps")
checked: Config.options.appearance.wallpaperTheming.enableQtApps
onCheckedChanged: {
Config.options.appearance.wallpaperTheming.enableQtApps = checked;
}
StyledToolTip {
content: Translation.tr("Shell & utilities theming must also be enabled")
}
}
ConfigSwitch {
text: Translation.tr("Terminal")
checked: Config.options.appearance.wallpaperTheming.enableTerminal
onCheckedChanged: {
Config.options.appearance.wallpaperTheming.enableTerminal = checked;
}
StyledToolTip {
content: Translation.tr("Shell & utilities theming must also be enabled")
}
}
}
}
}
@@ -1,374 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Policies")
ConfigRow {
ColumnLayout {
// Weeb policy
ContentSubsectionLabel {
text: Translation.tr("Weeb")
}
ConfigSelectionArray {
currentValue: Config.options.policies.weeb
configOptionName: "policies.weeb"
onSelected: newValue => {
Config.options.policies.weeb = newValue;
}
options: [
{
displayName: Translation.tr("No"),
value: 0
},
{
displayName: Translation.tr("Yes"),
value: 1
},
{
displayName: Translation.tr("Closet"),
value: 2
}
]
}
}
ColumnLayout {
// AI policy
ContentSubsectionLabel {
text: Translation.tr("AI")
}
ConfigSelectionArray {
currentValue: Config.options.policies.ai
configOptionName: "policies.ai"
onSelected: newValue => {
Config.options.policies.ai = newValue;
}
options: [
{
displayName: Translation.tr("No"),
value: 0
},
{
displayName: Translation.tr("Yes"),
value: 1
},
{
displayName: Translation.tr("Local only"),
value: 2
}
]
}
}
}
}
ContentSection {
title: Translation.tr("Bar")
ConfigSelectionArray {
currentValue: Config.options.bar.cornerStyle
configOptionName: "bar.cornerStyle"
onSelected: newValue => {
Config.options.bar.cornerStyle = newValue;
}
options: [
{
displayName: Translation.tr("Hug"),
value: 0
},
{
displayName: Translation.tr("Float"),
value: 1
},
{
displayName: Translation.tr("Plain rectangle"),
value: 2
}
]
}
ContentSubsection {
title: Translation.tr("Appearance")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr('Borderless')
checked: Config.options.bar.borderless
onCheckedChanged: {
Config.options.bar.borderless = checked;
}
}
ConfigSwitch {
text: Translation.tr('Show background')
checked: Config.options.bar.showBackground
onCheckedChanged: {
Config.options.bar.showBackground = checked;
}
StyledToolTip {
content: Translation.tr("Note: turning off can hurt readability")
}
}
}
}
ContentSubsection {
title: Translation.tr("Buttons")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Screen snip")
checked: Config.options.bar.utilButtons.showScreenSnip
onCheckedChanged: {
Config.options.bar.utilButtons.showScreenSnip = checked;
}
}
ConfigSwitch {
text: Translation.tr("Color picker")
checked: Config.options.bar.utilButtons.showColorPicker
onCheckedChanged: {
Config.options.bar.utilButtons.showColorPicker = checked;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Mic toggle")
checked: Config.options.bar.utilButtons.showMicToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showMicToggle = checked;
}
}
ConfigSwitch {
text: Translation.tr("Keyboard toggle")
checked: Config.options.bar.utilButtons.showKeyboardToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showKeyboardToggle = checked;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Dark/Light toggle")
checked: Config.options.bar.utilButtons.showDarkModeToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showDarkModeToggle = checked;
}
}
ConfigSwitch {
opacity: 0
enabled: false
}
}
}
ContentSubsection {
title: Translation.tr("Workspaces")
tooltip: Translation.tr("Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr('Show app icons')
checked: Config.options.bar.workspaces.showAppIcons
onCheckedChanged: {
Config.options.bar.workspaces.showAppIcons = checked;
}
}
ConfigSwitch {
text: Translation.tr('Always show numbers')
checked: Config.options.bar.workspaces.alwaysShowNumbers
onCheckedChanged: {
Config.options.bar.workspaces.alwaysShowNumbers = checked;
}
}
}
ConfigSpinBox {
text: Translation.tr("Workspaces shown")
value: Config.options.bar.workspaces.shown
from: 1
to: 30
stepSize: 1
onValueChanged: {
Config.options.bar.workspaces.shown = value;
}
}
ConfigSpinBox {
text: Translation.tr("Number show delay when pressing Super (ms)")
value: Config.options.bar.workspaces.showNumberDelay
from: 0
to: 1000
stepSize: 50
onValueChanged: {
Config.options.bar.workspaces.showNumberDelay = value;
}
}
}
ContentSubsection {
title: Translation.tr("Weather")
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.bar.weather.enable
onCheckedChanged: {
Config.options.bar.weather.enable = checked;
}
}
}
}
ContentSection {
title: Translation.tr("Battery")
ConfigRow {
uniform: true
ConfigSpinBox {
text: Translation.tr("Low warning")
value: Config.options.battery.low
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.low = value;
}
}
ConfigSpinBox {
text: Translation.tr("Critical warning")
value: Config.options.battery.critical
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.critical = value;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Automatic suspend")
checked: Config.options.battery.automaticSuspend
onCheckedChanged: {
Config.options.battery.automaticSuspend = checked;
}
StyledToolTip {
content: Translation.tr("Automatically suspends the system when battery is low")
}
}
ConfigSpinBox {
text: Translation.tr("Suspend at")
value: Config.options.battery.suspend
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.suspend = value;
}
}
}
}
ContentSection {
title: Translation.tr("Dock")
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.dock.enable
onCheckedChanged: {
Config.options.dock.enable = checked;
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Hover to reveal")
checked: Config.options.dock.hoverToReveal
onCheckedChanged: {
Config.options.dock.hoverToReveal = checked;
}
}
ConfigSwitch {
text: Translation.tr("Pinned on startup")
checked: Config.options.dock.pinnedOnStartup
onCheckedChanged: {
Config.options.dock.pinnedOnStartup = checked;
}
}
}
}
ContentSection {
title: Translation.tr("On-screen display")
ConfigSpinBox {
text: Translation.tr("Timeout (ms)")
value: Config.options.osd.timeout
from: 100
to: 3000
stepSize: 100
onValueChanged: {
Config.options.osd.timeout = value;
}
}
}
ContentSection {
title: Translation.tr("Overview")
ConfigSpinBox {
text: Translation.tr("Scale (%)")
value: Config.options.overview.scale * 100
from: 1
to: 100
stepSize: 1
onValueChanged: {
Config.options.overview.scale = value / 100;
}
}
ConfigRow {
uniform: true
ConfigSpinBox {
text: Translation.tr("Rows")
value: Config.options.overview.rows
from: 1
to: 20
stepSize: 1
onValueChanged: {
Config.options.overview.rows = value;
}
}
ConfigSpinBox {
text: Translation.tr("Columns")
value: Config.options.overview.columns
from: 1
to: 20
stepSize: 1
onValueChanged: {
Config.options.overview.columns = value;
}
}
}
}
ContentSection {
title: Translation.tr("Screenshot tool")
ConfigSwitch {
text: Translation.tr('Show regions of potential interest')
checked: Config.options.screenshotTool.showContentRegions
onCheckedChanged: {
Config.options.screenshotTool.showContentRegions = checked;
}
StyledToolTip {
content: Translation.tr("Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.")
}
}
}
}
@@ -1,233 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Audio")
ConfigSwitch {
text: Translation.tr("Earbang protection")
checked: Config.options.audio.protection.enable
onCheckedChanged: {
Config.options.audio.protection.enable = checked;
}
StyledToolTip {
content: Translation.tr("Prevents abrupt increments and restricts volume limit")
}
}
ConfigRow {
// uniform: true
ConfigSpinBox {
text: Translation.tr("Max allowed increase")
value: Config.options.audio.protection.maxAllowedIncrease
from: 0
to: 100
stepSize: 2
onValueChanged: {
Config.options.audio.protection.maxAllowedIncrease = value;
}
}
ConfigSpinBox {
text: Translation.tr("Volume limit")
value: Config.options.audio.protection.maxAllowed
from: 0
to: 100
stepSize: 2
onValueChanged: {
Config.options.audio.protection.maxAllowed = value;
}
}
}
}
ContentSection {
title: Translation.tr("AI")
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("System prompt")
text: Config.options.ai.systemPrompt
wrapMode: TextEdit.Wrap
onTextChanged: {
Qt.callLater(() => {
Config.options.ai.systemPrompt = text;
});
}
}
}
ContentSection {
title: Translation.tr("Battery")
ConfigRow {
uniform: true
ConfigSpinBox {
text: Translation.tr("Low warning")
value: Config.options.battery.low
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.low = value;
}
}
ConfigSpinBox {
text: Translation.tr("Critical warning")
value: Config.options.battery.critical
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.critical = value;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Automatic suspend")
checked: Config.options.battery.automaticSuspend
onCheckedChanged: {
Config.options.battery.automaticSuspend = checked;
}
StyledToolTip {
content: Translation.tr("Automatically suspends the system when battery is low")
}
}
ConfigSpinBox {
text: Translation.tr("Suspend at")
value: Config.options.battery.suspend
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.suspend = value;
}
}
}
}
ContentSection {
title: Translation.tr("Networking")
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("User agent (for services that require it)")
text: Config.options.networking.userAgent
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.networking.userAgent = text;
}
}
}
ContentSection {
title: Translation.tr("Resources")
ConfigSpinBox {
text: Translation.tr("Polling interval (ms)")
value: Config.options.resources.updateInterval
from: 100
to: 10000
stepSize: 100
onValueChanged: {
Config.options.resources.updateInterval = value;
}
}
}
ContentSection {
title: Translation.tr("Search")
ConfigSwitch {
text: Translation.tr("Use Levenshtein distance-based algorithm instead of fuzzy")
checked: Config.options.search.sloppy
onCheckedChanged: {
Config.options.search.sloppy = checked;
}
StyledToolTip {
content: Translation.tr("Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)")
}
}
ContentSubsection {
title: Translation.tr("Prefixes")
ConfigRow {
uniform: true
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Action")
text: Config.options.search.prefix.action
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.prefix.action = text;
}
}
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Clipboard")
text: Config.options.search.prefix.clipboard
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.prefix.clipboard = text;
}
}
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Emojis")
text: Config.options.search.prefix.emojis
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.prefix.emojis = text;
}
}
}
}
ContentSubsection {
title: Translation.tr("Web search")
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Base URL")
text: Config.options.search.engineBaseUrl
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.engineBaseUrl = text;
}
}
}
}
ContentSection {
title: Translation.tr("Time")
ContentSubsection {
title: Translation.tr("Format")
tooltip: ""
ConfigSelectionArray {
currentValue: Config.options.time.format
configOptionName: "time.format"
onSelected: newValue => {
Config.options.time.format = newValue;
}
options: [
{
displayName: Translation.tr("24h"),
value: "hh:mm"
},
{
displayName: Translation.tr("12h am/pm"),
value: "h:mm ap"
},
{
displayName: Translation.tr("12h AM/PM"),
value: "h:mm AP"
},
]
}
}
}
}
@@ -1,245 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
ContentPage {
baseWidth: lightDarkButtonGroup.implicitWidth
forceWidth: true
Process {
id: konachanWallProc
property string status: ""
command: ["bash", "-c", FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/random_konachan_wall.sh`)]
stdout: SplitParser {
onRead: data => {
console.log(`Konachan wall proc output: ${data}`);
konachanWallProc.status = data.trim();
}
}
}
ContentSection {
title: Translation.tr("Colors & Wallpaper")
// Light/Dark mode preference
ButtonGroup {
id: lightDarkButtonGroup
Layout.fillWidth: true
LightDarkPreferenceButton {
dark: false
}
LightDarkPreferenceButton {
dark: true
}
}
// Material palette selection
ContentSubsection {
title: Translation.tr("Material palette")
ConfigSelectionArray {
currentValue: Config.options.appearance.palette.type
configOptionName: "appearance.palette.type"
onSelected: (newValue) => {
Config.options.appearance.palette.type = newValue;
Quickshell.execDetached(["bash", "-c", `${Directories.wallpaperSwitchScriptPath} --noswitch`])
}
options: [
{"value": "auto", "displayName": Translation.tr("Auto")},
{"value": "scheme-content", "displayName": Translation.tr("Content")},
{"value": "scheme-expressive", "displayName": Translation.tr("Expressive")},
{"value": "scheme-fidelity", "displayName": Translation.tr("Fidelity")},
{"value": "scheme-fruit-salad", "displayName": Translation.tr("Fruit Salad")},
{"value": "scheme-monochrome", "displayName": Translation.tr("Monochrome")},
{"value": "scheme-neutral", "displayName": Translation.tr("Neutral")},
{"value": "scheme-rainbow", "displayName": Translation.tr("Rainbow")},
{"value": "scheme-tonal-spot", "displayName": Translation.tr("Tonal Spot")}
]
}
}
// Wallpaper selection
ContentSubsection {
title: Translation.tr("Wallpaper")
RowLayout {
Layout.alignment: Qt.AlignHCenter
RippleButtonWithIcon {
id: rndWallBtn
buttonRadius: Appearance.rounding.small
materialIcon: "wallpaper"
mainText: konachanWallProc.running ? Translation.tr("Be patient...") : Translation.tr("Random: Konachan")
onClicked: {
console.log(konachanWallProc.command.join(" "))
konachanWallProc.running = true;
}
StyledToolTip {
content: Translation.tr("Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers")
}
}
RippleButtonWithIcon {
materialIcon: "wallpaper"
StyledToolTip {
content: Translation.tr("Pick wallpaper image on your system")
}
onClicked: {
Quickshell.execDetached(`${Directories.wallpaperSwitchScriptPath}`)
}
mainContentComponent: Component {
RowLayout {
spacing: 10
StyledText {
font.pixelSize: Appearance.font.pixelSize.small
text: Translation.tr("Choose file")
color: Appearance.colors.colOnSecondaryContainer
}
RowLayout {
spacing: 3
KeyboardKey {
key: "Ctrl"
}
KeyboardKey {
key: "󰖳"
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: "+"
}
KeyboardKey {
key: "T"
}
}
}
}
}
}
}
StyledText {
Layout.topMargin: 5
Layout.alignment: Qt.AlignHCenter
text: Translation.tr("Alternatively use /dark, /light, /img in the launcher")
font.pixelSize: Appearance.font.pixelSize.smaller
color: Appearance.colors.colSubtext
}
}
ContentSection {
title: Translation.tr("Decorations & Effects")
ContentSubsection {
title: Translation.tr("Transparency")
ConfigRow {
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.appearance.transparency
onCheckedChanged: {
Config.options.appearance.transparency = checked;
}
StyledToolTip {
content: Translation.tr("Might look ass. Unsupported.")
}
}
}
}
ContentSubsection {
title: Translation.tr("Fake screen rounding")
ButtonGroup {
id: fakeScreenRoundingButtonGroup
property int selectedPolicy: Config.options.appearance.fakeScreenRounding
spacing: 2
SelectionGroupButton {
property int value: 0
leftmost: true
buttonText: Translation.tr("No")
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
Config.options.appearance.fakeScreenRounding = value;
}
}
SelectionGroupButton {
property int value: 1
buttonText: Translation.tr("Yes")
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
Config.options.appearance.fakeScreenRounding = value;
}
}
SelectionGroupButton {
property int value: 2
rightmost: true
buttonText: Translation.tr("When not fullscreen")
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
Config.options.appearance.fakeScreenRounding = value;
}
}
}
}
ContentSubsection {
title: Translation.tr("Shell windows")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Title bar")
checked: Config.options.windows.showTitlebar
onCheckedChanged: {
Config.options.windows.showTitlebar = checked;
}
}
ConfigSwitch {
text: Translation.tr("Center title")
checked: Config.options.windows.centerTitle
onCheckedChanged: {
Config.options.windows.centerTitle = checked;
}
}
}
}
ContentSubsection {
title: Translation.tr("Wallpaper parallax")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Depends on workspace")
checked: Config.options.background.parallax.enableWorkspace
onCheckedChanged: {
Config.options.background.parallax.enableWorkspace = checked;
}
}
ConfigSwitch {
text: Translation.tr("Depends on sidebars")
checked: Config.options.background.parallax.enableSidebar
onCheckedChanged: {
Config.options.background.parallax.enableSidebar = checked;
}
}
}
ConfigSpinBox {
text: Translation.tr("Preferred wallpaper zoom (%)")
value: Config.options.background.parallax.workspaceZoom * 100
from: 100
to: 150
stepSize: 1
onValueChanged: {
console.log(value/100)
Config.options.background.parallax.workspaceZoom = value / 100;
}
}
}
}
}
@@ -1,106 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
Item {
id: root
required property var scopeRoot
anchors.fill: parent
property var tabButtonList: [
...(Config.options.policies.ai !== 0 ? [{"icon": "neurology", "name": Translation.tr("Intelligence")}] : []),
{"icon": "translate", "name": Translation.tr("Translator")},
...(Config.options.policies.weeb === 1 ? [{"icon": "bookmark_heart", "name": Translation.tr("Anime")}] : [])
]
property int selectedTab: 0
function focusActiveItem() {
swipeView.currentItem.forceActiveFocus()
}
Keys.onPressed: (event) => {
if (event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_PageDown) {
root.selectedTab = Math.min(root.selectedTab + 1, root.tabButtonList.length - 1)
event.accepted = true;
}
else if (event.key === Qt.Key_PageUp) {
root.selectedTab = Math.max(root.selectedTab - 1, 0)
event.accepted = true;
}
else if (event.key === Qt.Key_Tab) {
root.selectedTab = (root.selectedTab + 1) % root.tabButtonList.length;
event.accepted = true;
}
else if (event.key === Qt.Key_Backtab) {
root.selectedTab = (root.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length;
event.accepted = true;
}
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: sidebarPadding
spacing: sidebarPadding
PrimaryTabBar { // Tab strip
id: tabBar
tabButtonList: root.tabButtonList
externalTrackedTab: root.selectedTab
function onCurrentIndexChanged(currentIndex) {
root.selectedTab = currentIndex
}
}
SwipeView { // Content pages
id: swipeView
Layout.topMargin: 5
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 10
currentIndex: tabBar.externalTrackedTab
onCurrentIndexChanged: {
tabBar.enableIndicatorAnimation = true
root.selectedTab = currentIndex
}
clip: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: swipeView.width
height: swipeView.height
radius: Appearance.rounding.small
}
}
contentChildren: [
...(Config.options.policies.ai !== 0 ? [aiChat.createObject()] : []),
translator.createObject(),
...(Config.options.policies.weeb === 0 ? [] : [anime.createObject()])
]
}
Component {
id: aiChat
AiChat {}
}
Component {
id: translator
Translator {}
}
Component {
id: anime
Anime {}
}
}
}
@@ -1,287 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Io
import Quickshell
Rectangle {
id: root
property int messageIndex
property var messageData
property var messageInputField
property real messagePadding: 7
property real contentSpacing: 3
property bool enableMouseSelection: false
property bool renderMarkdown: true
property bool editing: false
property list<var> messageBlocks: StringUtils.splitMarkdownBlocks(root.messageData?.content)
anchors.left: parent?.left
anchors.right: parent?.right
implicitHeight: columnLayout.implicitHeight + root.messagePadding * 2
radius: Appearance.rounding.normal
color: Appearance.colors.colLayer1
function saveMessage() {
if (!root.editing) return;
// Get all Loader children (each represents a segment)
const segments = messageContentColumnLayout.children
.map(child => child.segment)
.filter(segment => (segment));
// Reconstruct markdown
const newContent = segments.map(segment => {
if (segment.type === "code") {
const lang = segment.lang ? segment.lang : "";
// Remove trailing newlines
const code = segment.content.replace(/\n+$/, "");
return "```" + lang + "\n" + code + "\n```";
} else {
return segment.content;
}
}).join("");
root.editing = false
root.messageData.content = newContent;
}
Keys.onPressed: (event) => {
if ( // Prevent de-select
event.key === Qt.Key_Control ||
event.key == Qt.Key_Shift ||
event.key == Qt.Key_Alt ||
event.key == Qt.Key_Meta
) {
event.accepted = true
}
// Ctrl + S to save
if ((event.key === Qt.Key_S) && event.modifiers == Qt.ControlModifier) {
root.saveMessage();
event.accepted = true;
}
}
ColumnLayout { // Main layout of the whole thing
id: columnLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: messagePadding
spacing: root.contentSpacing
RowLayout { // Header
spacing: 15
Layout.fillWidth: true
Rectangle { // Name
id: nameWrapper
color: Appearance.colors.colSecondaryContainer
// color: "transparent"
radius: Appearance.rounding.small
implicitHeight: Math.max(nameRowLayout.implicitHeight + 5 * 2, 30)
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
RowLayout {
id: nameRowLayout
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 10
anchors.rightMargin: 10
spacing: 7
Item {
Layout.alignment: Qt.AlignVCenter
Layout.fillHeight: true
implicitWidth: messageData?.role == 'assistant' ? modelIcon.width : roleIcon.implicitWidth
implicitHeight: messageData?.role == 'assistant' ? modelIcon.height : roleIcon.implicitHeight
CustomIcon {
id: modelIcon
anchors.centerIn: parent
visible: messageData?.role == 'assistant' && Ai.models[messageData?.model].icon
width: Appearance.font.pixelSize.large
height: Appearance.font.pixelSize.large
source: messageData?.role == 'assistant' ? Ai.models[messageData?.model].icon :
messageData?.role == 'user' ? 'linux-symbolic' : 'desktop-symbolic'
colorize: true
color: Appearance.m3colors.m3onSecondaryContainer
}
MaterialSymbol {
id: roleIcon
anchors.centerIn: parent
visible: !modelIcon.visible
iconSize: Appearance.font.pixelSize.larger
color: Appearance.m3colors.m3onSecondaryContainer
text: messageData?.role == 'user' ? 'person' :
messageData?.role == 'interface' ? 'settings' :
messageData?.role == 'assistant' ? 'neurology' :
'computer'
}
}
StyledText {
id: providerName
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
elide: Text.ElideRight
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.m3colors.m3onSecondaryContainer
text: messageData?.role == 'assistant' ? Ai.models[messageData?.model].name :
(messageData?.role == 'user' && SystemInfo.username) ? SystemInfo.username :
Translation.tr("Interface")
}
}
}
Button { // Not visible to model
id: modelVisibilityIndicator
visible: messageData?.role == 'interface'
implicitWidth: 16
implicitHeight: 30
Layout.alignment: Qt.AlignVCenter
background: Item
MaterialSymbol {
id: notVisibleToModelText
anchors.centerIn: parent
iconSize: Appearance.font.pixelSize.small
color: Appearance.colors.colSubtext
text: "visibility_off"
}
StyledToolTip {
content: Translation.tr("Not visible to model")
}
}
ButtonGroup {
spacing: 5
AiMessageControlButton {
id: copyButton
buttonIcon: activated ? "inventory" : "content_copy"
onClicked: {
Quickshell.clipboardText = root.messageData?.content
copyButton.activated = true
copyIconTimer.restart()
}
Timer {
id: copyIconTimer
interval: 1500
repeat: false
onTriggered: {
copyButton.activated = false
}
}
StyledToolTip {
content: Translation.tr("Copy")
}
}
AiMessageControlButton {
id: editButton
activated: root.editing
enabled: root.messageData?.done ?? false
buttonIcon: "edit"
onClicked: {
root.editing = !root.editing
if (!root.editing) { // Save changes
root.saveMessage()
}
}
StyledToolTip {
content: root.editing ? Translation.tr("Save") : Translation.tr("Edit")
}
}
AiMessageControlButton {
id: toggleMarkdownButton
activated: !root.renderMarkdown
buttonIcon: "code"
onClicked: {
root.renderMarkdown = !root.renderMarkdown
}
StyledToolTip {
content: Translation.tr("View Markdown source")
}
}
AiMessageControlButton {
id: deleteButton
buttonIcon: "close"
onClicked: {
Ai.removeMessage(root.messageIndex)
}
StyledToolTip {
content: Translation.tr("Delete")
}
}
}
}
ColumnLayout { // Message content
id: messageContentColumnLayout
spacing: 0
Repeater {
model: root.messageBlocks.length
delegate: Loader {
required property int index
property var thisBlock: root.messageBlocks[index]
Layout.fillWidth: true
// property var segment: thisBlock
property var segmentContent: thisBlock.content
property var segmentLang: thisBlock.lang
property var messageData: root.messageData
property var editing: root.editing
property var renderMarkdown: root.renderMarkdown
property var enableMouseSelection: root.enableMouseSelection
property bool thinking: root.messageData?.thinking ?? true
property bool done: root.messageData?.done ?? false
property bool completed: thisBlock.completed ?? false
source: thisBlock.type === "code" ? "MessageCodeBlock.qml" :
thisBlock.type === "think" ? "MessageThinkBlock.qml" :
"MessageTextBlock.qml"
}
}
}
Flow { // Annotations
id: annotationFlowLayout
visible: root.messageData?.annotationSources?.length > 0
spacing: 5
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft
Repeater {
model: ScriptModel {
values: root.messageData?.annotationSources || []
}
delegate: AnnotationSourceButton {
id: annotationButton
displayText: modelData.text
url: modelData.url
}
}
}
}
}
@@ -1,142 +0,0 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Hyprland
ColumnLayout {
id: root
// These are needed on the parent loader
property bool editing: parent?.editing ?? false
property bool renderMarkdown: parent?.renderMarkdown ?? true
property bool enableMouseSelection: parent?.enableMouseSelection ?? false
property string segmentContent: parent?.segmentContent ?? ({})
property var messageData: parent?.messageData ?? {}
property bool done: parent?.done ?? true
property list<string> renderedLatexHashes: []
property string renderedSegmentContent: ""
Layout.fillWidth: true
Timer {
id: renderTimer
interval: 1000
repeat: false
onTriggered: {
renderLatex()
for (const hash of renderedLatexHashes) {
handleRenderedLatex(hash, true);
}
}
}
function renderLatex() {
// Regex for $...$, $$...$$, \[...\]
// Note: This is a simple approach and may need refinement for edge cases
let regex = /(\$\$([\s\S]+?)\$\$)|(\$([^\$]+?)\$)|(\\\[((?:.|\n)+?)\\\])|(\\\(([\s\S]+?)\\\))/g;
let match;
while ((match = regex.exec(segmentContent)) !== null) {
let expression = match[1] || match[2] || match[3] || match[4] || match[5] || match[6] || match[7] || match[8];
if (expression) {
Qt.callLater(() => {
const [renderHash, isNew] = LatexRenderer.requestRender(expression.trim());
if (!renderedLatexHashes.includes(renderHash)) {
renderedLatexHashes.push(renderHash);
}
});
}
}
}
function handleRenderedLatex(hash, force = false) {
if (renderedLatexHashes.includes(hash) || force) {
const imagePath = LatexRenderer.renderedImagePaths[hash];
const markdownImage = `![latex](${imagePath})`;
const expression = LatexRenderer.processedExpressions[hash];
renderedSegmentContent = renderedSegmentContent.replace(expression, markdownImage);
}
}
onDoneChanged: {
renderTimer.restart();
}
onEditingChanged: {
if (!editing) {
renderLatex()
} else {
// console.log("Editing mode enabled", segmentContent)
textArea.text = segmentContent
}
}
onSegmentContentChanged: {
// console.log("Segment content changed: " + segmentContent);
renderedSegmentContent = segmentContent;
if (!root.editing && segmentContent) {
root.renderLatex();
}
}
onRenderedSegmentContentChanged: {
// console.log("Rendered segment content changed: " + renderedSegmentContent);
if (renderedSegmentContent) {
textArea.text = renderedSegmentContent;
}
}
// When something finishes rendering
// 1. Check if the hash is in the list
// 2. If it is, replace the expression with the image path
Connections {
target: LatexRenderer
function onRenderFinished(hash, imagePath) {
const expression = LatexRenderer.processedExpressions[hash];
// console.log("Render finished: " + hash + " " + expression);
handleRenderedLatex(hash);
}
}
TextArea {
id: textArea
Layout.fillWidth: true
readOnly: !editing
selectByMouse: enableMouseSelection || editing
renderType: Text.NativeRendering
font.family: Appearance.font.family.reading
font.hintingPreference: Font.PreferNoHinting // Prevent weird bold text
font.pixelSize: Appearance.font.pixelSize.small
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
selectionColor: Appearance.colors.colSecondaryContainer
wrapMode: TextEdit.Wrap
color: messageData.thinking ? Appearance.colors.colSubtext : Appearance.colors.colOnLayer1
textFormat: renderMarkdown ? TextEdit.MarkdownText : TextEdit.PlainText
text: Translation.tr("Waiting for response...")
onTextChanged: {
if (!root.editing) return
segmentContent = text
}
onLinkActivated: (link) => {
Qt.openUrlExternally(link)
Hyprland.dispatch("global quickshell:sidebarLeftClose")
}
MouseArea { // Pointing hand for links
anchors.fill: parent
acceptedButtons: Qt.NoButton // Only for hover
hoverEnabled: true
cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor :
(enableMouseSelection || editing) ? Qt.IBeamCursor : Qt.ArrowCursor
}
}
}
@@ -1,80 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import "./notifications"
import "./volumeMixer"
import qs
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Rectangle {
id: root
radius: Appearance.rounding.normal
color: Appearance.colors.colLayer1
property int selectedTab: 0
property var tabButtonList: [{"icon": "notifications", "name": Translation.tr("Notifications")}, {"icon": "volume_up", "name": Translation.tr("Volume mixer")}]
Keys.onPressed: (event) => {
if (event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp) {
if (event.key === Qt.Key_PageDown) {
root.selectedTab = Math.min(root.selectedTab + 1, root.tabButtonList.length - 1)
} else if (event.key === Qt.Key_PageUp) {
root.selectedTab = Math.max(root.selectedTab - 1, 0)
}
event.accepted = true;
}
if (event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_Tab) {
root.selectedTab = (root.selectedTab + 1) % root.tabButtonList.length
} else if (event.key === Qt.Key_Backtab) {
root.selectedTab = (root.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length
}
event.accepted = true;
}
}
ColumnLayout {
anchors.margins: 5
anchors.fill: parent
spacing: 0
PrimaryTabBar {
id: tabBar
tabButtonList: root.tabButtonList
externalTrackedTab: root.selectedTab
function onCurrentIndexChanged(currentIndex) {
root.selectedTab = currentIndex
}
}
SwipeView {
id: swipeView
Layout.topMargin: 5
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 10
currentIndex: root.selectedTab
onCurrentIndexChanged: {
tabBar.enableIndicatorAnimation = true
root.selectedTab = currentIndex
}
clip: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: swipeView.width
height: swipeView.height
radius: Appearance.rounding.small
}
}
NotificationList {}
VolumeMixer {}
}
}
}
@@ -1,250 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import "./quickToggles/"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell.Io
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: root
property int sidebarWidth: Appearance.sizes.sidebarWidth
property int sidebarPadding: 12
property string settingsQmlPath: Quickshell.configPath("settings.qml")
PanelWindow {
id: sidebarRoot
visible: GlobalStates.sidebarRightOpen
function hide() {
GlobalStates.sidebarRightOpen = false
}
exclusiveZone: 0
implicitWidth: sidebarWidth
WlrLayershell.namespace: "quickshell:sidebarRight"
// Hyprland 0.49: Focus is always exclusive and setting this breaks mouse focus grab
// WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
color: "transparent"
anchors {
top: true
right: true
bottom: true
}
HyprlandFocusGrab {
id: grab
windows: [ sidebarRoot ]
active: GlobalStates.sidebarRightOpen
onCleared: () => {
if (!active) sidebarRoot.hide()
}
}
Loader {
id: sidebarContentLoader
active: GlobalStates.sidebarRightOpen
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
left: parent.left
topMargin: Appearance.sizes.hyprlandGapsOut
rightMargin: Appearance.sizes.hyprlandGapsOut
bottomMargin: Appearance.sizes.hyprlandGapsOut
leftMargin: Appearance.sizes.elevationMargin
}
width: sidebarWidth - Appearance.sizes.hyprlandGapsOut - Appearance.sizes.elevationMargin
height: parent.height - Appearance.sizes.hyprlandGapsOut * 2
focus: GlobalStates.sidebarRightOpen
Keys.onPressed: (event) => {
if (event.key === Qt.Key_Escape) {
sidebarRoot.hide();
}
}
sourceComponent: Item {
implicitHeight: sidebarRightBackground.implicitHeight
implicitWidth: sidebarRightBackground.implicitWidth
StyledRectangularShadow {
target: sidebarRightBackground
}
Rectangle {
id: sidebarRightBackground
anchors.fill: parent
implicitHeight: parent.height - Appearance.sizes.hyprlandGapsOut * 2
implicitWidth: sidebarWidth - Appearance.sizes.hyprlandGapsOut * 2
color: Appearance.colors.colLayer0
border.width: 1
border.color: Appearance.m3colors.m3outlineVariant
radius: Appearance.rounding.screenRounding - Appearance.sizes.hyprlandGapsOut + 1
ColumnLayout {
anchors.fill: parent
anchors.margins: sidebarPadding
spacing: sidebarPadding
RowLayout {
Layout.fillHeight: false
spacing: 10
Layout.margins: 10
Layout.topMargin: 5
Layout.bottomMargin: 0
Item {
implicitWidth: distroIcon.width
implicitHeight: distroIcon.height
CustomIcon {
id: distroIcon
width: 25
height: 25
source: SystemInfo.distroIcon
}
ColorOverlay {
anchors.fill: distroIcon
source: distroIcon
color: Appearance.colors.colOnLayer0
}
}
StyledText {
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnLayer0
text: Translation.tr("Uptime: %1").arg(DateTime.uptime)
textFormat: Text.MarkdownText
}
Item {
Layout.fillWidth: true
}
ButtonGroup {
QuickToggleButton {
toggled: false
buttonIcon: "restart_alt"
onClicked: {
Hyprland.dispatch("reload")
Quickshell.reload(true)
}
StyledToolTip {
content: Translation.tr("Reload Hyprland & Quickshell")
}
}
QuickToggleButton {
toggled: false
buttonIcon: "settings"
onClicked: {
Hyprland.dispatch("global quickshell:sidebarRightClose")
Quickshell.execDetached(["qs", "-p", root.settingsQmlPath])
}
StyledToolTip {
content: Translation.tr("Settings")
}
}
QuickToggleButton {
toggled: false
buttonIcon: "power_settings_new"
onClicked: {
Hyprland.dispatch("global quickshell:sessionOpen")
}
StyledToolTip {
content: Translation.tr("Session")
}
}
}
}
ButtonGroup {
Layout.alignment: Qt.AlignHCenter
spacing: 5
padding: 5
color: Appearance.colors.colLayer1
NetworkToggle {}
BluetoothToggle {}
NightLight {}
GameMode {}
IdleInhibitor {}
EasyEffectsToggle {}
CloudflareWarp {}
}
// Center widget group
CenterWidgetGroup {
focus: sidebarRoot.visible
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
Layout.fillWidth: true
}
BottomWidgetGroup {
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: false
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
}
}
}
}
}
}
IpcHandler {
target: "sidebarRight"
function toggle(): void {
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
if(GlobalStates.sidebarRightOpen) Notifications.timeoutAll();
}
function close(): void {
GlobalStates.sidebarRightOpen = false;
}
function open(): void {
GlobalStates.sidebarRightOpen = true;
Notifications.timeoutAll();
}
}
GlobalShortcut {
name: "sidebarRightToggle"
description: "Toggles right sidebar on press"
onPressed: {
GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen;
if(GlobalStates.sidebarRightOpen) Notifications.timeoutAll();
}
}
GlobalShortcut {
name: "sidebarRightOpen"
description: "Opens right sidebar on press"
onPressed: {
GlobalStates.sidebarRightOpen = true;
Notifications.timeoutAll();
}
}
GlobalShortcut {
name: "sidebarRightClose"
description: "Closes right sidebar on press"
onPressed: {
GlobalStates.sidebarRightOpen = false;
}
}
}
@@ -1,118 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import qs
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Item {
id: root
NotificationListView { // Scrollable window
id: listview
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: statusRow.top
anchors.bottomMargin: 5
clip: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: listview.width
height: listview.height
radius: Appearance.rounding.normal
}
}
popup: false
}
// Placeholder when list is empty
Item {
anchors.fill: listview
visible: opacity > 0
opacity: (Notifications.list.length === 0) ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Appearance.animation.menuDecel.duration
easing.type: Appearance.animation.menuDecel.type
}
}
ColumnLayout {
anchors.centerIn: parent
spacing: 5
MaterialSymbol {
Layout.alignment: Qt.AlignHCenter
iconSize: 55
color: Appearance.m3colors.m3outline
text: "notifications_active"
}
StyledText {
Layout.alignment: Qt.AlignHCenter
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.m3colors.m3outline
horizontalAlignment: Text.AlignHCenter
text: Translation.tr("No notifications")
}
}
}
Item {
id: statusRow
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
Layout.fillWidth: true
implicitHeight: Math.max(
controls.implicitHeight,
statusText.implicitHeight
)
StyledText {
id: statusText
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
horizontalAlignment: Text.AlignHCenter
text: Translation.tr("%1 notifications").arg(Notifications.list.length)
opacity: Notifications.list.length > 0 ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
ButtonGroup {
id: controls
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 5
NotificationStatusButton {
buttonIcon: "notifications_paused"
buttonText: Translation.tr("Silent")
toggled: Notifications.silent
onClicked: () => {
Notifications.silent = !Notifications.silent;
}
}
NotificationStatusButton {
buttonIcon: "clear_all"
buttonText: Translation.tr("Clear")
onClicked: () => {
Notifications.discardAllNotifications()
}
}
}
}
}
@@ -1,36 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
QuickToggleButton {
toggled: Bluetooth.bluetoothEnabled
buttonIcon: Bluetooth.bluetoothConnected ? "bluetooth_connected" : Bluetooth.bluetoothEnabled ? "bluetooth" : "bluetooth_disabled"
onClicked: {
toggleBluetooth.running = true
}
altAction: () => {
Quickshell.execDetached(["bash", "-c", `${Config.options.apps.bluetooth}`])
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
Process {
id: toggleBluetooth
command: ["bash", "-c", `bluetoothctl power ${Bluetooth.bluetoothEnabled ? "off" : "on"}`]
onRunningChanged: {
if(!running) {
Bluetooth.update()
}
}
}
StyledToolTip {
content: Translation.tr("%1 | Right-click to configure").arg(
(Bluetooth.bluetoothEnabled && Bluetooth.bluetoothDeviceName.length > 0) ?
Bluetooth.bluetoothDeviceName : Translation.tr("Bluetooth"))
}
}
@@ -1,49 +0,0 @@
import qs.modules.common.widgets
import qs
import Quickshell.Io
import Quickshell
import Quickshell.Hyprland
QuickToggleButton {
id: root
toggled: false
visible: false
buttonIcon: "instant_mix"
onClicked: {
if (toggled) {
root.toggled = false
Quickshell.execDetached(["pkill", "easyeffects"])
} else {
root.toggled = true
Quickshell.execDetached(["easyeffects", "--gapplication-service"])
}
}
altAction: () => {
Quickshell.execDetached(["easyeffects"])
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
Process {
id: fetchAvailability
running: true
command: ["bash", "-c", "command -v easyeffects"]
onExited: (exitCode, exitStatus) => {
root.visible = exitCode === 0
}
}
Process {
id: fetchActiveState
running: true
command: ["pidof", "easyeffects"]
onExited: (exitCode, exitStatus) => {
root.toggled = exitCode === 0
}
}
StyledToolTip {
content: Translation.tr("EasyEffects | Right-click to configure")
}
}
@@ -1,31 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs
import Quickshell.Io
import Quickshell
QuickToggleButton {
id: root
toggled: false
buttonIcon: "coffee"
onClicked: {
if (toggled) {
root.toggled = false
Quickshell.execDetached(["pkill", "wayland-idle"]) // pkill doesn't accept too long names
} else {
root.toggled = true
Quickshell.execDetached([`${Directories.scriptPath}/wayland-idle-inhibitor.py`])
}
}
Process {
id: fetchActiveState
running: true
command: ["pidof", "wayland-idle-inhibitor.py"]
onExited: (exitCode, exitStatus) => {
root.toggled = exitCode === 0
}
}
StyledToolTip {
content: Translation.tr("Keep system awake")
}
}
@@ -1,34 +0,0 @@
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import "../"
import qs
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
QuickToggleButton {
toggled: Network.networkName.length > 0 && Network.networkName != "lo"
buttonIcon: Network.materialSymbol
onClicked: {
toggleNetwork.running = true
}
altAction: () => {
Quickshell.execDetached(["bash", "-c", `${Network.ethernet ? Config.options.apps.networkEthernet : Config.options.apps.network}`])
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
Process {
id: toggleNetwork
command: ["bash", "-c", "nmcli radio wifi | grep -q enabled && nmcli radio wifi off || nmcli radio wifi on"]
onRunningChanged: {
if(!running) {
Network.update()
}
}
}
StyledToolTip {
content: Translation.tr("%1 | Right-click to configure").arg(Network.networkName)
}
}
@@ -1,41 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs
import Quickshell.Io
QuickToggleButton {
id: nightLightButton
property bool enabled: false
toggled: enabled
buttonIcon: "nightlight"
onClicked: {
nightLightButton.enabled = !nightLightButton.enabled
if (enabled) {
nightLightOn.startDetached()
}
else {
nightLightOff.startDetached()
}
}
Process {
id: nightLightOn
command: ["gammastep"]
}
Process {
id: nightLightOff
command: ["pkill", "gammastep"]
}
Process {
id: updateNightLightState
running: true
command: ["pidof", "gammastep"]
stdout: SplitParser {
onRead: (data) => { // if not empty then set toggled to true
nightLightButton.enabled = data.length > 0
}
}
}
StyledToolTip {
content: Translation.tr("Night Light")
}
}
@@ -1,282 +0,0 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.services
import qs
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Pipewire
Item {
id: root
property bool showDeviceSelector: false
property bool deviceSelectorInput
property int dialogMargins: 16
property PwNode selectedDevice
readonly property list<PwNode> appPwNodes: Pipewire.nodes.values.filter((node) => {
// return node.type == "21" // Alternative, not as clean
return node.isSink && node.isStream
})
function showDeviceSelectorDialog(input: bool) {
root.selectedDevice = null
root.showDeviceSelector = true
root.deviceSelectorInput = input
}
Keys.onPressed: (event) => {
// Close dialog on pressing Esc if open
if (event.key === Qt.Key_Escape && root.showDeviceSelector) {
root.showDeviceSelector = false
event.accepted = true;
}
}
ColumnLayout {
anchors.fill: parent
Item {
Layout.fillWidth: true
Layout.fillHeight: true
ListView {
id: listView
model: root.appPwNodes
clip: true
anchors {
fill: parent
topMargin: 10
bottomMargin: 10
}
spacing: 6
delegate: VolumeMixerEntry {
// Layout.fillWidth: true
anchors {
left: parent.left
right: parent.right
leftMargin: 10
rightMargin: 10
}
required property var modelData
node: modelData
}
}
// Placeholder when list is empty
Item {
anchors.fill: listView
visible: opacity > 0
opacity: (root.appPwNodes.length === 0) ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Appearance.animation.menuDecel.duration
easing.type: Appearance.animation.menuDecel.type
}
}
ColumnLayout {
anchors.centerIn: parent
spacing: 5
MaterialSymbol {
Layout.alignment: Qt.AlignHCenter
iconSize: 55
color: Appearance.m3colors.m3outline
text: "brand_awareness"
}
StyledText {
Layout.alignment: Qt.AlignHCenter
font.pixelSize: Appearance.font.pixelSize.normal
color: Appearance.m3colors.m3outline
horizontalAlignment: Text.AlignHCenter
text: Translation.tr("No audio source")
}
}
}
}
// Separator
Rectangle {
color: Appearance.m3colors.m3outlineVariant
implicitHeight: 1
Layout.fillWidth: true
}
// Device selector
ButtonGroup {
id: deviceSelectorRowLayout
Layout.fillWidth: true
Layout.fillHeight: false
AudioDeviceSelectorButton {
Layout.fillWidth: true
input: false
onClicked: root.showDeviceSelectorDialog(input)
}
AudioDeviceSelectorButton {
Layout.fillWidth: true
input: true
onClicked: root.showDeviceSelectorDialog(input)
}
}
}
// Device selector dialog
Item {
anchors.fill: parent
z: 9999
visible: opacity > 0
opacity: root.showDeviceSelector ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
}
Rectangle { // Scrim
id: scrimOverlay
anchors.fill: parent
radius: Appearance.rounding.small
color: Appearance.colors.colScrim
MouseArea {
hoverEnabled: true
anchors.fill: parent
preventStealing: true
propagateComposedEvents: false
}
}
Rectangle { // The dialog
id: dialog
color: Appearance.colors.colSurfaceContainerHigh
radius: Appearance.rounding.normal
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: 30
implicitHeight: dialogColumnLayout.implicitHeight
ColumnLayout {
id: dialogColumnLayout
anchors.fill: parent
spacing: 16
StyledText {
id: dialogTitle
Layout.topMargin: dialogMargins
Layout.leftMargin: dialogMargins
Layout.rightMargin: dialogMargins
Layout.alignment: Qt.AlignLeft
color: Appearance.m3colors.m3onSurface
font.pixelSize: Appearance.font.pixelSize.larger
text: root.deviceSelectorInput ? Translation.tr("Select input device") : Translation.tr("Select output device")
}
Rectangle {
color: Appearance.m3colors.m3outline
implicitHeight: 1
Layout.fillWidth: true
Layout.leftMargin: dialogMargins
Layout.rightMargin: dialogMargins
}
Flickable {
id: dialogFlickable
Layout.fillWidth: true
clip: true
implicitHeight: Math.min(scrimOverlay.height - dialogMargins * 8 - dialogTitle.height - dialogButtonsRowLayout.height, devicesColumnLayout.implicitHeight)
contentHeight: devicesColumnLayout.implicitHeight
ColumnLayout {
id: devicesColumnLayout
anchors.fill: parent
Layout.fillWidth: true
spacing: 0
Repeater {
model: ScriptModel {
values: Pipewire.nodes.values.filter(node => {
return !node.isStream && node.isSink !== root.deviceSelectorInput && node.audio
})
}
// This could and should be refractored, but all data becomes null when passed wtf
delegate: StyledRadioButton {
id: radioButton
required property var modelData
Layout.leftMargin: root.dialogMargins
Layout.rightMargin: root.dialogMargins
Layout.fillWidth: true
description: modelData.description
checked: modelData.id === Pipewire.defaultAudioSink?.id
Connections {
target: root
function onShowDeviceSelectorChanged() {
if(!root.showDeviceSelector) return;
radioButton.checked = (modelData.id === Pipewire.defaultAudioSink?.id)
}
}
onCheckedChanged: {
if (checked) {
root.selectedDevice = modelData
}
}
}
}
Item {
implicitHeight: dialogMargins
}
}
}
Rectangle {
color: Appearance.m3colors.m3outline
implicitHeight: 1
Layout.fillWidth: true
Layout.leftMargin: dialogMargins
Layout.rightMargin: dialogMargins
}
RowLayout {
id: dialogButtonsRowLayout
Layout.bottomMargin: dialogMargins
Layout.leftMargin: dialogMargins
Layout.rightMargin: dialogMargins
Layout.alignment: Qt.AlignRight
DialogButton {
buttonText: Translation.tr("Cancel")
onClicked: {
root.showDeviceSelector = false
}
}
DialogButton {
buttonText: Translation.tr("OK")
onClicked: {
root.showDeviceSelector = false
if (root.selectedDevice) {
if (root.deviceSelectorInput) {
Pipewire.preferredDefaultAudioSource = root.selectedDevice
} else {
Pipewire.preferredDefaultAudioSink = root.selectedDevice
}
}
}
}
}
}
}
}
}
-552
View File
@@ -1,552 +0,0 @@
//@ pragma UseQApplication
//@ pragma Env QS_NO_RELOAD_POPUP=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
// Adjust this to make it smaller or larger
//@ pragma Env QT_SCALE_FACTOR=1
pragma ComponentBehavior: "Bound"
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import Quickshell.Wayland
import Quickshell.Hyprland
ShellRoot {
id: root
property string screenshotDir: Directories.screenshotTemp
property color overlayColor: "#77111111"
property color genericContentColor: Qt.alpha(root.overlayColor, 0.9)
property color genericContentForeground: "#ddffffff"
property color selectionBorderColor: "#ddf1f1f1"
property color selectionFillColor: "#33ffffff"
property color windowBorderColor: "#dda0c0da"
property color windowFillColor: "#22a0c0da"
property color imageBorderColor: "#ddf1d1ff"
property color imageFillColor: "#33f1d1ff"
property color onBorderColor: "#ff000000"
property real standardRounding: 4
readonly property var windows: HyprlandData.windowList
readonly property var layers: HyprlandData.layers
readonly property real falsePositivePreventionRatio: 0.5
// Force initialization of some singletons
Component.onCompleted: {
MaterialThemeLoader.reapplyTheme();
}
component TargetRegion: Rectangle {
id: regionRect
property bool showIcon: false
property bool targeted: false
property color borderColor
property color fillColor: "transparent"
property string text: ""
property real textPadding: 10
z: 2
color: fillColor
border.color: borderColor
border.width: targeted ? 3 : 1
radius: root.standardRounding
Rectangle {
id: regionLabelBackground
property real verticalPadding: 5
property real horizontalPadding: 10
radius: 10
color: root.genericContentColor
border.width: 1
border.color: Appearance.m3colors.m3outlineVariant
anchors {
top: parent.top
left: parent.left
topMargin: regionRect.textPadding
leftMargin: regionRect.textPadding
}
implicitWidth: regionInfoRow.implicitWidth + horizontalPadding * 2
implicitHeight: regionInfoRow.implicitHeight + verticalPadding * 2
RowLayout {
id: regionInfoRow
anchors.centerIn: parent
spacing: 8
Loader {
id: regionIconLoader
active: regionRect.showIcon
visible: active
sourceComponent: IconImage {
implicitSize: Appearance.font.pixelSize.larger
source: Quickshell.iconPath(AppSearch.guessIcon(regionRect.text), "image-missing")
}
}
StyledText {
id: regionText
text: regionRect.text
color: root.genericContentForeground
}
}
}
}
Variants {
model: Quickshell.screens
PanelWindow {
id: panelWindow
required property var modelData
readonly property HyprlandMonitor hyprlandMonitor: Hyprland.monitorFor(modelData)
readonly property real monitorScale: hyprlandMonitor.scale
readonly property real monitorOffsetX: hyprlandMonitor.x
readonly property real monitorOffsetY: hyprlandMonitor.y
property int activeWorkspaceId: hyprlandMonitor.activeWorkspace?.id ?? 0
property string screenshotPath: `${root.screenshotDir}/image-${modelData.name}`
property real dragStartX: 0
property real dragStartY: 0
property real draggingX: 0
property real draggingY: 0
property real dragDiffX: 0
property real dragDiffY: 0
property bool draggedAway: (dragDiffX !== 0 || dragDiffY !== 0)
property bool dragging: false
property var mouseButton: null
property var imageRegions: []
readonly property list<var> windowRegions: filterWindowRegionsByLayers(
root.windows.filter(w => w.workspace.id === panelWindow.activeWorkspaceId),
panelWindow.layerRegions
).map(window => {
return {
at: [window.at[0] - panelWindow.monitorOffsetX, window.at[1] - panelWindow.monitorOffsetY],
size: [window.size[0], window.size[1]],
class: window.class,
title: window.title,
}
})
readonly property list<var> layerRegions: {
const layersOfThisMonitor = root.layers[panelWindow.hyprlandMonitor.name]
const topLayers = layersOfThisMonitor.levels["2"]
const nonBarTopLayers = topLayers
.filter(layer => !(layer.namespace.includes(":bar") || layer.namespace.includes(":dock")))
.map(layer => {
return {
at: [layer.x, layer.y],
size: [layer.w, layer.h],
namespace: layer.namespace,
}
})
const offsetAdjustedLayers = nonBarTopLayers.map(layer => {
return {
at: [layer.at[0] - panelWindow.monitorOffsetX, layer.at[1] - panelWindow.monitorOffsetY],
size: layer.size,
namespace: layer.namespace,
}
});
return offsetAdjustedLayers;
}
property real targetedRegionX: -1
property real targetedRegionY: -1
property real targetedRegionWidth: 0
property real targetedRegionHeight: 0
function intersectionOverUnion(regionA, regionB) {
// region: { at: [x, y], size: [w, h] }
const ax1 = regionA.at[0], ay1 = regionA.at[1];
const ax2 = ax1 + regionA.size[0], ay2 = ay1 + regionA.size[1];
const bx1 = regionB.at[0], by1 = regionB.at[1];
const bx2 = bx1 + regionB.size[0], by2 = by1 + regionB.size[1];
const interX1 = Math.max(ax1, bx1);
const interY1 = Math.max(ay1, by1);
const interX2 = Math.min(ax2, bx2);
const interY2 = Math.min(ay2, by2);
const interArea = Math.max(0, interX2 - interX1) * Math.max(0, interY2 - interY1);
const areaA = (ax2 - ax1) * (ay2 - ay1);
const areaB = (bx2 - bx1) * (by2 - by1);
const unionArea = areaA + areaB - interArea;
return unionArea > 0 ? interArea / unionArea : 0;
}
function filterOverlappingImageRegions(regions) {
let keep = [];
let removed = new Set();
for (let i = 0; i < regions.length; ++i) {
if (removed.has(i)) continue;
let regionA = regions[i];
for (let j = i + 1; j < regions.length; ++j) {
if (removed.has(j)) continue;
let regionB = regions[j];
if (intersectionOverUnion(regionA, regionB) > 0) {
// Compare areas
let areaA = regionA.size[0] * regionA.size[1];
let areaB = regionB.size[0] * regionB.size[1];
if (areaA <= areaB) {
removed.add(j);
} else {
removed.add(i);
}
}
}
}
for (let i = 0; i < regions.length; ++i) {
if (!removed.has(i)) keep.push(regions[i]);
}
return keep;
}
function filterWindowRegionsByLayers(windowRegions, layerRegions) {
return windowRegions.filter(windowRegion => {
for (let i = 0; i < layerRegions.length; ++i) {
if (intersectionOverUnion(windowRegion, layerRegions[i]) > 0)
return false;
}
return true;
});
}
function filterImageRegions(regions, windowRegions, threshold = 0.1) {
// Remove image regions that overlap too much with any window region
let filtered = regions.filter(region => {
for (let i = 0; i < windowRegions.length; ++i) {
if (intersectionOverUnion(region, windowRegions[i]) > threshold)
return false;
}
return true;
});
// Remove overlapping image regions, keep only the smaller one
return filterOverlappingImageRegions(filtered);
}
function updateTargetedRegion(x, y) {
// Image regions
const clickedRegion = panelWindow.imageRegions.find(region => {
return region.at[0] <= x && x <= region.at[0] + region.size[0] && region.at[1] <= y && y <= region.at[1] + region.size[1];
});
if (clickedRegion) {
panelWindow.targetedRegionX = clickedRegion.at[0];
panelWindow.targetedRegionY = clickedRegion.at[1];
panelWindow.targetedRegionWidth = clickedRegion.size[0];
panelWindow.targetedRegionHeight = clickedRegion.size[1];
return;
}
// Layer regions
const clickedLayer = panelWindow.layerRegions.find(region => {
return region.at[0] <= x && x <= region.at[0] + region.size[0] && region.at[1] <= y && y <= region.at[1] + region.size[1];
});
if (clickedLayer) {
panelWindow.targetedRegionX = clickedLayer.at[0];
panelWindow.targetedRegionY = clickedLayer.at[1];
panelWindow.targetedRegionWidth = clickedLayer.size[0];
panelWindow.targetedRegionHeight = clickedLayer.size[1];
return;
}
// Window regions
const clickedWindow = panelWindow.windowRegions.find(region => {
return region.at[0] <= x && x <= region.at[0] + region.size[0] && region.at[1] <= y && y <= region.at[1] + region.size[1];
});
if (clickedWindow) {
panelWindow.targetedRegionX = clickedWindow.at[0];
panelWindow.targetedRegionY = clickedWindow.at[1];
panelWindow.targetedRegionWidth = clickedWindow.size[0];
panelWindow.targetedRegionHeight = clickedWindow.size[1];
return;
}
panelWindow.targetedRegionX = -1;
panelWindow.targetedRegionY = -1;
panelWindow.targetedRegionWidth = 0;
panelWindow.targetedRegionHeight = 0;
}
property real regionWidth: Math.abs(draggingX - dragStartX)
property real regionHeight: Math.abs(draggingY - dragStartY)
property real regionX: Math.min(dragStartX, draggingX)
property real regionY: Math.min(dragStartY, draggingY)
visible: false
screen: modelData
WlrLayershell.namespace: "quickshell:screenshot"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
exclusionMode: ExclusionMode.Ignore
anchors {
left: true
right: true
top: true
bottom: true
}
Process {
id: screenshotProcess
running: true
command: ["bash", "-c", `mkdir -p '${StringUtils.shellSingleQuoteEscape(root.screenshotDir)}' && grim -o '${StringUtils.shellSingleQuoteEscape(modelData.name)}' '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}'`]
onExited: (exitCode, exitStatus) => {
panelWindow.visible = true;
imageDetectionProcess.running = true;
}
}
Process {
id: imageDetectionProcess
command: ["bash", "-c", `${Directories.scriptPath}/images/find_regions.py `
+ `--hyprctl `
+ `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}' `
+ `--max-width ${Math.round(panelWindow.screen.width * root.falsePositivePreventionRatio)} `
+ `--max-height ${Math.round(panelWindow.screen.height * root.falsePositivePreventionRatio)} `]
stdout: StdioCollector {
id: imageDimensionCollector
onStreamFinished: {
imageRegions = filterImageRegions(
JSON.parse(imageDimensionCollector.text),
panelWindow.windowRegions
);
}
}
}
Process {
id: snipProc
function snip() {
if (panelWindow.regionWidth <= 0 || panelWindow.regionHeight <= 0) {
console.warn("Invalid region size, skipping snip.");
Qt.quit();
}
snipProc.startDetached();
Qt.quit();
}
command: ["bash", "-c",
`magick ${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)} `
+ `-crop ${panelWindow.regionWidth * panelWindow.monitorScale}x${panelWindow.regionHeight * panelWindow.monitorScale}+${panelWindow.regionX * panelWindow.monitorScale}+${panelWindow.regionY * panelWindow.monitorScale} - `
+ `| ${panelWindow.mouseButton === Qt.LeftButton ? "wl-copy" : "swappy -f -"}`]
}
ScreencopyView {
anchors.fill: parent
live: false
captureSource: modelData
focus: panelWindow.visible
Keys.onPressed: (event) => { // Esc to close
if (event.key === Qt.Key_Escape) {
Qt.quit();
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.CrossCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
// Controls
onPressed: mouse => {
panelWindow.dragStartX = mouse.x;
panelWindow.dragStartY = mouse.y;
panelWindow.draggingX = mouse.x;
panelWindow.draggingY = mouse.y;
panelWindow.dragging = true;
panelWindow.mouseButton = mouse.button;
}
onReleased: mouse => {
// Detect if it was a click
// Image regions
if (panelWindow.draggingX === panelWindow.dragStartX && panelWindow.draggingY === panelWindow.dragStartY) {
if (panelWindow.targetedRegionX >= 0 && panelWindow.targetedRegionY >= 0) {
panelWindow.regionX = panelWindow.targetedRegionX;
panelWindow.regionY = panelWindow.targetedRegionY;
panelWindow.regionWidth = panelWindow.targetedRegionWidth;
panelWindow.regionHeight = panelWindow.targetedRegionHeight;
}
}
snipProc.snip();
}
onPositionChanged: mouse => {
if (panelWindow.dragging) {
panelWindow.draggingX = mouse.x;
panelWindow.draggingY = mouse.y;
panelWindow.dragDiffX = mouse.x - panelWindow.dragStartX;
panelWindow.dragDiffY = mouse.y - panelWindow.dragStartY;
}
panelWindow.updateTargetedRegion(mouse.x, mouse.y);
}
// Overlay to darken screen
Rectangle { // Base
id: overlayRect
z: 0
anchors.fill: parent
color: root.overlayColor
layer.enabled: true
}
Rectangle {
// TODO: Make this mask the base instead of just overlaying a border
z: 1
anchors {
left: parent.left
top: parent.top
leftMargin: panelWindow.regionX
topMargin: panelWindow.regionY
}
width: panelWindow.regionWidth
height: panelWindow.regionHeight
color: "transparent"
border.color: root.selectionBorderColor
border.width: 2
radius: root.standardRounding
}
// Instructions
Rectangle {
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: (Appearance.sizes.barHeight - implicitHeight) / 2
}
opacity: panelWindow.dragging ? 0 : 1
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
color: root.genericContentColor
radius: 10
border.width: 1
border.color: Appearance.m3colors.m3outlineVariant
implicitWidth: instructionsRow.implicitWidth + 10 * 2
implicitHeight: instructionsRow.implicitHeight + 5 * 2
RowLayout {
id: instructionsRow
anchors.centerIn: parent
Item {
Layout.fillHeight: true
implicitWidth: screenshotRegionIcon.implicitWidth
MaterialSymbol {
id: screenshotRegionIcon
anchors.centerIn: parent
iconSize: Appearance.font.pixelSize.larger
text: "screenshot_region"
color: root.genericContentForeground
}
}
StyledText {
text: Translation.tr("Drag or click a region • LMB: Copy • RMB: Edit")
color: root.genericContentForeground
}
}
}
// Window regions
Repeater {
model: ScriptModel {
values: panelWindow.windowRegions
}
delegate: TargetRegion {
z: 2
required property var modelData
showIcon: true
targeted: !panelWindow.draggedAway &&
(panelWindow.targetedRegionX === modelData.at[0]
&& panelWindow.targetedRegionY === modelData.at[1]
&& panelWindow.targetedRegionWidth === modelData.size[0]
&& panelWindow.targetedRegionHeight === modelData.size[1])
opacity: panelWindow.draggedAway ? 0 : 1
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
x: modelData.at[0]
y: modelData.at[1]
width: modelData.size[0]
height: modelData.size[1]
borderColor: root.windowBorderColor
fillColor: targeted ? root.windowFillColor : "transparent"
border.width: targeted ? 4 : 2
text: `${modelData.class}`
radius: Appearance.rounding.windowRounding
}
}
// Layer regions
Repeater {
model: ScriptModel {
values: panelWindow.layerRegions
}
delegate: TargetRegion {
z: 3
required property var modelData
targeted: !panelWindow.draggedAway &&
(panelWindow.targetedRegionX === modelData.at[0]
&& panelWindow.targetedRegionY === modelData.at[1]
&& panelWindow.targetedRegionWidth === modelData.size[0]
&& panelWindow.targetedRegionHeight === modelData.size[1])
opacity: panelWindow.draggedAway ? 0 : 1
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
x: modelData.at[0]
y: modelData.at[1]
width: modelData.size[0]
height: modelData.size[1]
borderColor: root.windowBorderColor
fillColor: targeted ? root.windowFillColor : "transparent"
border.width: targeted ? 4 : 2
text: `${modelData.namespace}`
radius: Appearance.rounding.windowRounding
}
}
// Image regions
Repeater {
model: ScriptModel {
values: Config.options.screenshotTool.showContentRegions ? panelWindow.imageRegions : []
}
delegate: TargetRegion {
z: 4
required property var modelData
targeted: !panelWindow.draggedAway &&
(panelWindow.targetedRegionX === modelData.at[0]
&& panelWindow.targetedRegionY === modelData.at[1]
&& panelWindow.targetedRegionWidth === modelData.size[0]
&& panelWindow.targetedRegionHeight === modelData.size[1])
opacity: panelWindow.draggedAway ? 0 : 1
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
x: modelData.at[0]
y: modelData.at[1]
width: modelData.size[0]
height: modelData.size[1]
borderColor: root.imageBorderColor
fillColor: targeted ? root.imageFillColor : "transparent"
border.width: targeted ? 4 : 2
text: "Content region"
}
}
}
}
}
}
}
@@ -1,341 +0,0 @@
#!/usr/bin/env python3
# Disclaimer: This script was ai-generated and went through minimal revision.
import os
os.environ["OPENCV_LOG_LEVEL"] = "SILENT"
import cv2
import numpy as np
import argparse
import json
def center_crop(img, target_w, target_h):
h, w = img.shape[:2]
if w == target_w and h == target_h:
return img
x1 = max(0, (w - target_w) // 2)
y1 = max(0, (h - target_h) // 2)
x2 = x1 + target_w
y2 = y1 + target_h
return img[y1:y2, x1:x2]
def find_least_busy_region(image_path, region_width=300, region_height=200, screen_width=None, screen_height=None, verbose=False, stride=2, screen_mode="fill", horizontal_padding=50, vertical_padding=50):
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise FileNotFoundError(f"Image not found: {image_path}")
orig_h, orig_w = img.shape
scale = 1.0
if screen_width is not None and screen_height is not None:
scale_w = screen_width / orig_w
scale_h = screen_height / orig_h
if screen_mode == "fill":
scale = max(scale_w, scale_h)
else:
scale = min(scale_w, scale_h)
new_w = int(orig_w * scale)
new_h = int(orig_h * scale)
if verbose:
print(f"Scaling image from {orig_w}x{orig_h} to {new_w}x{new_h} (scale: {scale:.3f}, mode: {screen_mode})")
img = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LANCZOS4)
img = center_crop(img, screen_width, screen_height)
if verbose:
print(f"Cropped image to {screen_width}x{screen_height}")
else:
if verbose:
print(f"Using original image size: {orig_w}x{orig_h}")
arr = img.astype(np.float64)
h, w = arr.shape
# Use OpenCV's integral for fast computation
integral = cv2.integral(arr, sdepth=cv2.CV_64F)[1:,1:]
integral_sq = cv2.integral(arr**2, sdepth=cv2.CV_64F)[1:,1:]
def region_sum(ii, x1, y1, x2, y2):
total = ii[y2, x2]
if x1 > 0:
total -= ii[y2, x1-1]
if y1 > 0:
total -= ii[y1-1, x2]
if x1 > 0 and y1 > 0:
total += ii[y1-1, x1-1]
return total
min_var = None
min_coords = (0, 0)
area = region_width * region_height
x_start = horizontal_padding
y_start = vertical_padding
x_end = w - region_width - horizontal_padding + 1
y_end = h - region_height - vertical_padding + 1
for y in range(y_start, max(y_end, y_start+1), stride):
for x in range(x_start, max(x_end, x_start+1), stride):
x1, y1 = x, y
x2, y2 = x + region_width - 1, y + region_height - 1
s = region_sum(integral, x1, y1, x2, y2)
s2 = region_sum(integral_sq, x1, y1, x2, y2)
mean = s / area
var = (s2 / area) - (mean ** 2)
if (min_var is None) or (var < min_var):
min_var = var
min_coords = (x, y)
return min_coords, min_var
def find_largest_region(image_path, screen_width=None, screen_height=None, verbose=False, stride=2, screen_mode="fill", threshold=100.0, aspect_ratio=1.0, horizontal_padding=50, vertical_padding=50):
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if img is None:
raise FileNotFoundError(f"Image not found: {image_path}")
orig_h, orig_w = img.shape
scale = 1.0
if screen_width is not None and screen_height is not None:
scale_w = screen_width / orig_w
scale_h = screen_height / orig_h
if screen_mode == "fill":
scale = max(scale_w, scale_h)
else:
scale = min(scale_w, scale_h)
new_w = int(orig_w * scale)
new_h = int(orig_h * scale)
if verbose:
print(f"Scaling image from {orig_w}x{orig_h} to {new_w}x{new_h} (scale: {scale:.3f}, mode: {screen_mode})")
img = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LANCZOS4)
img = center_crop(img, screen_width, screen_height)
if verbose:
print(f"Cropped image to {screen_width}x{screen_height}")
else:
if verbose:
print(f"Using original image size: {orig_w}x{orig_h}")
arr = img.astype(np.float64)
h, w = arr.shape
# Use OpenCV's integral for fast computation
integral = cv2.integral(arr, sdepth=cv2.CV_64F)[1:,1:]
integral_sq = cv2.integral(arr**2, sdepth=cv2.CV_64F)[1:,1:]
def region_sum(ii, x1, y1, x2, y2):
total = ii[y2, x2]
if x1 > 0:
total -= ii[y2, x1-1]
if y1 > 0:
total -= ii[y1-1, x2]
if x1 > 0 and y1 > 0:
total += ii[y1-1, x1-1]
return total
min_size = 10
max_size = min(h, int(w / aspect_ratio)) if aspect_ratio >= 1.0 else min(int(h * aspect_ratio), w)
best = None
best_size = min_size
while min_size <= max_size:
mid = (min_size + max_size) // 2
if aspect_ratio >= 1.0:
region_h = mid
region_w = int(mid * aspect_ratio)
else:
region_w = mid
region_h = int(mid / aspect_ratio)
if region_w > w or region_h > h:
max_size = mid - 1
continue
found = False
x_start = horizontal_padding
y_start = vertical_padding
x_end = w - region_w - horizontal_padding + 1
y_end = h - region_h - vertical_padding + 1
for y in range(y_start, max(y_end, y_start+1), stride):
for x in range(x_start, max(x_end, x_start+1), stride):
x1, y1 = x, y
x2, y2 = x + region_w - 1, y + region_h - 1
s = region_sum(integral, x1, y1, x2, y2)
s2 = region_sum(integral_sq, x1, y1, x2, y2)
area = region_w * region_h
mean = s / area
var = (s2 / area) - (mean ** 2)
if var <= threshold:
found = True
best = (x, y, region_w, region_h, var)
break
if found:
break
if found:
best_size = mid
min_size = mid + 1
else:
max_size = mid - 1
if best:
x, y, region_w, region_h, var = best
center_x = x + region_w // 2
center_y = y + region_h // 2
return (center_x, center_y), (region_w, region_h), var
else:
return None, (0, 0), None
def draw_region(image_path, coords, region_width=300, region_height=200, output_path='output.png', screen_width=None, screen_height=None, screen_mode="fill"):
img = cv2.imread(image_path)
if img is None:
raise FileNotFoundError(f"Image not found: {image_path}")
orig_h, orig_w = img.shape[:2]
if screen_width is not None and screen_height is not None:
scale_w = screen_width / orig_w
scale_h = screen_height / orig_h
if screen_mode == "fill":
scale = max(scale_w, scale_h)
else:
scale = min(scale_w, scale_h)
new_w = int(orig_w * scale)
new_h = int(orig_h * scale)
img = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LANCZOS4)
img = center_crop(img, screen_width, screen_height)
x, y = coords
cv2.rectangle(img, (x, y), (x+region_width-1, y+region_height-1), (0,0,255), 3)
cv2.imwrite(output_path, img)
print(f"Saved output image with rectangle at {output_path}")
def draw_largest_region(image_path, center, size, output_path='output.png', screen_width=None, screen_height=None, screen_mode="fill"):
img = cv2.imread(image_path)
if img is None:
raise FileNotFoundError(f"Image not found: {image_path}")
orig_h, orig_w = img.shape[:2]
if screen_width is not None and screen_height is not None:
scale_w = screen_width / orig_w
scale_h = screen_height / orig_h
if screen_mode == "fill":
scale = max(scale_w, scale_h)
else:
scale = min(scale_w, scale_h)
new_w = int(orig_w * scale)
new_h = int(orig_h * scale)
img = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LANCZOS4)
img = center_crop(img, screen_width, screen_height)
cx, cy = center
region_w, region_h = size
x1 = cx - region_w // 2
y1 = cy - region_h // 2
x2 = cx + region_w // 2 - 1
y2 = cy + region_h // 2 - 1
cv2.rectangle(img, (x1, y1), (x2, y2), (255,0,0), 3)
cv2.imwrite(output_path, img)
print(f"Saved output image with largest region at {output_path}")
def get_dominant_color(image_path, x, y, w, h, screen_width=None, screen_height=None, screen_mode="fill"):
img = cv2.imread(image_path)
if img is None:
raise FileNotFoundError(f"Image not found: {image_path}")
orig_h, orig_w = img.shape[:2]
if screen_width is not None and screen_height is not None:
scale_w = screen_width / orig_w
scale_h = screen_height / orig_h
if screen_mode == "fill":
scale = max(scale_w, scale_h)
else:
scale = min(scale_w, scale_h)
new_w = int(orig_w * scale)
new_h = int(orig_h * scale)
img = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LANCZOS4)
img = center_crop(img, screen_width, screen_height)
# Ensure region is within bounds
x = max(0, x)
y = max(0, y)
w = max(1, min(w, img.shape[1] - x))
h = max(1, min(h, img.shape[0] - y))
region = img[y:y+h, x:x+w]
if region.size == 0 or region.shape[0] == 0 or region.shape[1] == 0:
return [0, 0, 0]
region = region.reshape((-1, 3))
# Filter out black pixels (optional, improves accuracy for some images)
non_black = region[np.any(region > 10, axis=1)]
if non_black.shape[0] == 0:
non_black = region
region = np.float32(non_black)
if region.shape[0] < 3:
return [int(x) for x in np.mean(region, axis=0)]
# K-means to find dominant color
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = min(3, region.shape[0])
_, labels, centers = cv2.kmeans(region, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
counts = np.bincount(labels.flatten())
dominant = centers[np.argmax(counts)]
return [int(x) for x in dominant]
def main():
parser = argparse.ArgumentParser(description="Find least busy region in an image and output a JSON. Made for determining a suitable position for a wallpaper widget.")
parser.add_argument("image_path", help="Path to the input image")
parser.add_argument("--width", type=int, default=300, help="Region width")
parser.add_argument("--height", type=int, default=200, help="Region height")
parser.add_argument("-v", "--visual-output", action="store_true", help="Output image with rectangle")
parser.add_argument("--screen-width", type=int, default=1920, help="Screen width for wallpaper scaling")
parser.add_argument("--screen-height", type=int, default=1080, help="Screen height for wallpaper scaling")
parser.add_argument("--stride", type=int, default=10, help="Step size for sliding window (higher is faster, less precise)")
parser.add_argument("--screen-mode", choices=["fill", "fit"], default="fill", help="Wallpaper scaling mode: 'fill' (default) or 'fit'")
parser.add_argument("--verbose", action="store_true", help="Print verbose output")
parser.add_argument("-l", "--largest-region", action="store_true", help="Find the largest region under the variance threshold and output its center")
parser.add_argument("-t", "--variance-threshold", type=float, default=1000.0, help="Variance threshold for largest region mode")
parser.add_argument("--aspect-ratio", type=float, default=1.78, help="Aspect ratio (width/height) for largest region mode")
parser.add_argument("--horizontal-padding", "-hp", type=int, default=50, help="Minimum horizontal distance from region to image edge")
parser.add_argument("--vertical-padding", "-vp", type=int, default=50, help="Minimum vertical distance from region to image edge")
args = parser.parse_args()
if args.largest_region:
center, size, var = find_largest_region(
args.image_path,
screen_width=args.screen_width,
screen_height=args.screen_height,
verbose=args.verbose,
stride=args.stride,
screen_mode=args.screen_mode,
threshold=args.variance_threshold,
aspect_ratio=args.aspect_ratio,
horizontal_padding=args.horizontal_padding,
vertical_padding=args.vertical_padding
)
if center:
if args.visual_output:
draw_largest_region(args.image_path, center, size, screen_width=args.screen_width, screen_height=args.screen_height, screen_mode=args.screen_mode)
# Extract dominant color
cx, cy = center
region_w, region_h = size
x1 = cx - region_w // 2
y1 = cy - region_h // 2
dominant_color = get_dominant_color(
args.image_path, x1, y1, region_w, region_h,
screen_width=args.screen_width, screen_height=args.screen_height, screen_mode=args.screen_mode
)
dominant_color_hex = '#{:02x}{:02x}{:02x}'.format(*dominant_color)
print(json.dumps({
"center_x": center[0],
"center_y": center[1],
"width": size[0],
"height": size[1],
"variance": var,
"dominant_color": dominant_color_hex
}))
else:
print(json.dumps({"error": "No region found under the threshold."}))
return
coords, variance = find_least_busy_region(
args.image_path,
region_width=args.width,
region_height=args.height,
screen_width=args.screen_width,
screen_height=args.screen_height,
verbose=args.verbose,
stride=args.stride,
screen_mode=args.screen_mode,
horizontal_padding=args.horizontal_padding,
vertical_padding=args.vertical_padding
)
if args.visual_output:
draw_region(args.image_path, coords, region_width=args.width, region_height=args.height, screen_width=args.screen_width, screen_height=args.screen_height, screen_mode=args.screen_mode)
# Output JSON with center point
center_x = coords[0] + args.width // 2
center_y = coords[1] + args.height // 2
dominant_color = get_dominant_color(
args.image_path, coords[0], coords[1], args.width, args.height,
screen_width=args.screen_width, screen_height=args.screen_height, screen_mode=args.screen_mode
)
dominant_color_hex = '#{:02x}{:02x}{:02x}'.format(*dominant_color)
print(json.dumps({
"center_x": center_x,
"center_y": center_y,
"width": args.width,
"height": args.height,
"variance": variance,
"dominant_color": dominant_color_hex
}))
if __name__ == "__main__":
main()
@@ -1,86 +0,0 @@
#!/usr/bin/env -S\_/bin/sh\_-xc\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
# From https://github.com/stwa/wayland-idle-inhibitor
# License: WTFPL Version 2
import sys
from dataclasses import dataclass
from signal import SIGINT, SIGTERM, signal
from threading import Event
import setproctitle
from pywayland.client.display import Display
from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import (
ZwpIdleInhibitManagerV1,
)
from pywayland.protocol.wayland.wl_compositor import WlCompositor
from pywayland.protocol.wayland.wl_registry import WlRegistryProxy
from pywayland.protocol.wayland.wl_surface import WlSurface
@dataclass
class GlobalRegistry:
surface: WlSurface | None = None
inhibit_manager: ZwpIdleInhibitManagerV1 | None = None
def handle_registry_global(
wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int
) -> None:
global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry()
if iface_name == "wl_compositor":
compositor = wl_registry.bind(id_num, WlCompositor, version)
global_registry.surface = compositor.create_surface() # type: ignore
elif iface_name == "zwp_idle_inhibit_manager_v1":
global_registry.inhibit_manager = wl_registry.bind(
id_num, ZwpIdleInhibitManagerV1, version
)
def main() -> None:
done = Event()
signal(SIGINT, lambda _, __: done.set())
signal(SIGTERM, lambda _, __: done.set())
global_registry = GlobalRegistry()
display = Display()
display.connect()
registry = display.get_registry() # type: ignore
registry.user_data = global_registry
registry.dispatcher["global"] = handle_registry_global
def shutdown() -> None:
display.dispatch()
display.roundtrip()
display.disconnect()
display.dispatch()
display.roundtrip()
if global_registry.surface is None or global_registry.inhibit_manager is None:
print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.")
shutdown()
sys.exit(1)
inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore
global_registry.surface
)
display.dispatch()
display.roundtrip()
print("Inhibiting idle...")
done.wait()
print("Shutting down...")
inhibitor.destroy()
shutdown()
if __name__ == "__main__":
setproctitle.setproctitle("wayland-idle-inhibitor.py")
main()
-54
View File
@@ -1,54 +0,0 @@
import qs.modules.common
import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
pragma Singleton
pragma ComponentBehavior: Bound
/**
* A nice wrapper for default Pipewire audio sink and source.
*/
Singleton {
id: root
property bool ready: Pipewire.defaultAudioSink?.ready ?? false
property PwNode sink: Pipewire.defaultAudioSink
property PwNode source: Pipewire.defaultAudioSource
signal sinkProtectionTriggered(string reason);
PwObjectTracker {
objects: [sink, source]
}
Connections { // Protection against sudden volume changes
target: sink?.audio ?? null
property bool lastReady: false
property real lastVolume: 0
function onVolumeChanged() {
if (!Config.options.audio.protection.enable) return;
if (!lastReady) {
lastVolume = sink.audio.volume;
lastReady = true;
return;
}
const newVolume = sink.audio.volume;
const maxAllowedIncrease = Config.options.audio.protection.maxAllowedIncrease / 100;
const maxAllowed = Config.options.audio.protection.maxAllowed / 100;
if (newVolume - lastVolume > maxAllowedIncrease) {
sink.audio.volume = lastVolume;
root.sinkProtectionTriggered("Illegal increment");
} else if (newVolume > maxAllowed) {
root.sinkProtectionTriggered("Exceeded max allowed");
sink.audio.volume = Math.min(lastVolume, maxAllowed);
}
if (sink.ready && (isNaN(sink.audio.volume) || sink.audio.volume === undefined || sink.audio.volume === null)) {
sink.audio.volume = 0;
}
lastVolume = sink.audio.volume;
}
}
}
@@ -1,50 +0,0 @@
pragma Singleton
import qs
import qs.modules.common
import Quickshell
import Quickshell.Services.UPower
Singleton {
property bool available: UPower.displayDevice.isLaptopBattery
property var chargeState: UPower.displayDevice.state
property bool isCharging: chargeState == UPowerDeviceState.Charging
property bool isPluggedIn: isCharging || chargeState == UPowerDeviceState.PendingCharge
property real percentage: UPower.displayDevice.percentage
readonly property bool allowAutomaticSuspend: Config.options.battery.automaticSuspend
property bool isLow: percentage <= Config.options.battery.low / 100
property bool isCritical: percentage <= Config.options.battery.critical / 100
property bool isSuspending: percentage <= Config.options.battery.suspend / 100
property bool isLowAndNotCharging: isLow && !isCharging
property bool isCriticalAndNotCharging: isCritical && !isCharging
property bool isSuspendingAndNotCharging: allowAutomaticSuspend && isSuspending && !isCharging
onIsLowAndNotChargingChanged: {
if (available && isLowAndNotCharging) Quickshell.execDetached([
"notify-send",
Translation.tr("Low battery"),
Translation.tr("Consider plugging in your device"),
"-u", "critical",
"-a", "Shell"
])
}
onIsCriticalAndNotChargingChanged: {
if (available && isCriticalAndNotCharging) Quickshell.execDetached([
"notify-send",
Translation.tr("Critically low battery"),
Translation.tr("Please charge!\nAutomatic suspend triggers at %1").arg(Config.options.battery.suspend),
"-u", "critical",
"-a", "Shell"
]);
}
onIsSuspendingAndNotChargingChanged: {
if (available && isSuspendingAndNotCharging) {
Quickshell.execDetached(["bash", "-c", `systemctl suspend || loginctl suspend`]);
}
}
}
@@ -1,73 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import Quickshell;
import Quickshell.Io;
import QtQuick;
/**
* Basic polled Bluetooth state.
*/
Singleton {
id: root
property int updateInterval: 1000
property string bluetoothDeviceName: ""
property string bluetoothDeviceAddress: ""
property bool bluetoothEnabled: false
property bool bluetoothConnected: false
function update() {
updateBluetoothDevice.running = true
updateBluetoothStatus.running = true
updateBluetoothEnabled.running = true
}
Timer {
interval: 10
running: true
repeat: true
onTriggered: {
update()
interval = root.updateInterval
}
}
// Check if Bluetooth is enabled (controller powered on)
Process {
id: updateBluetoothEnabled
command: ["sh", "-c", "bluetoothctl show | grep -q 'Powered: yes' && echo 1 || echo 0"]
running: true
stdout: SplitParser {
onRead: data => {
root.bluetoothEnabled = (parseInt(data) === 1)
}
}
}
// Get the name and address of the first connected Bluetooth device
Process {
id: updateBluetoothDevice
command: ["sh", "-c", "bluetoothctl info | awk -F': ' '/Name: /{name=$2} /Device /{addr=$2} END{print name \":\" addr}'"]
running: true
stdout: SplitParser {
onRead: data => {
let parts = data.split(":")
root.bluetoothDeviceName = parts[0] || ""
root.bluetoothDeviceAddress = parts[1] || ""
}
}
}
// Check if any device is connected
Process {
id: updateBluetoothStatus
command: ["sh", "-c", "bluetoothctl info | grep -q 'Connected: yes' && echo 1 || echo 0"]
running: true
stdout: SplitParser {
onRead: data => {
root.bluetoothConnected = (parseInt(data) === 1)
}
}
}
}
@@ -1,152 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
// From https://github.com/caelestia-dots/shell/ (`quickshell` branch) with modifications.
// License: GPLv3
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import QtQuick
/**
* For managing brightness of monitors. Supports both brightnessctl and ddcutil.
*/
Singleton {
id: root
signal brightnessChanged()
property var ddcMonitors: []
readonly property list<BrightnessMonitor> monitors: Quickshell.screens.map(screen => monitorComp.createObject(root, {
screen
}))
function getMonitorForScreen(screen: ShellScreen): var {
return monitors.find(m => m.screen === screen);
}
function increaseBrightness(): void {
const focusedName = Hyprland.focusedMonitor.name;
const monitor = monitors.find(m => focusedName === m.screen.name);
if (monitor)
monitor.setBrightness(monitor.brightness + 0.05);
}
function decreaseBrightness(): void {
const focusedName = Hyprland.focusedMonitor.name;
const monitor = monitors.find(m => focusedName === m.screen.name);
if (monitor)
monitor.setBrightness(monitor.brightness - 0.05);
}
reloadableId: "brightness"
onMonitorsChanged: {
ddcMonitors = [];
ddcProc.running = true;
}
Process {
id: ddcProc
command: ["ddcutil", "detect", "--brief"]
stdout: SplitParser {
splitMarker: "\n\n"
onRead: data => {
if (data.startsWith("Display ")) {
const lines = data.split("\n").map(l => l.trim());
root.ddcMonitors.push({
model: lines.find(l => l.startsWith("Monitor:")).split(":")[2],
busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1]
});
}
}
}
onExited: root.ddcMonitorsChanged()
}
Process {
id: setProc
}
component BrightnessMonitor: QtObject {
id: monitor
required property ShellScreen screen
readonly property bool isDdc: root.ddcMonitors.some(m => m.model === screen.model)
readonly property string busNum: root.ddcMonitors.find(m => m.model === screen.model)?.busNum ?? ""
property real brightness
property bool ready: false
onBrightnessChanged: {
if (monitor.ready) {
root.brightnessChanged();
}
}
function initialize() {
monitor.ready = false;
initProc.command = isDdc ? ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"] : ["sh", "-c", `echo "a b c $(brightnessctl g) $(brightnessctl m)"`];
initProc.running = true;
}
readonly property Process initProc: Process {
stdout: SplitParser {
onRead: data => {
const [, , , current, max] = data.split(" ");
monitor.brightness = parseInt(current) / parseInt(max);
monitor.ready = true;
}
}
}
function setBrightness(value: real): void {
value = Math.max(0.01, Math.min(1, value));
const rounded = Math.round(value * 100);
if (Math.round(brightness * 100) === rounded)
return;
brightness = value;
setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rounded] : ["brightnessctl", "s", `${rounded}%`, "--quiet"];
setProc.startDetached();
}
Component.onCompleted: {
initialize();
}
onBusNumChanged: {
initialize();
}
}
Component {
id: monitorComp
BrightnessMonitor {}
}
IpcHandler {
target: "brightness"
function increment() {
onPressed: root.increaseBrightness()
}
function decrement() {
onPressed: root.decreaseBrightness()
}
}
GlobalShortcut {
name: "brightnessIncrease"
description: "Increase brightness"
onPressed: root.increaseBrightness()
}
GlobalShortcut {
name: "brightnessDecrease"
description: "Decrease brightness"
onPressed: root.decreaseBrightness()
}
}
@@ -1,133 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
/**
* Provides access to some Hyprland data not available in Quickshell.Hyprland.
*/
Singleton {
id: root
property var windowList: []
property var addresses: []
property var windowByAddress: ({})
property var workspaces: []
property var workspaceIds: []
property var workspaceById: ({})
property var activeWorkspace: null
property var monitors: []
property var layers: ({})
function updateWindowList() {
getClients.running = true;
}
function updateLayers() {
getLayers.running = true;
}
function updateMonitors() {
getMonitors.running = true;
}
function updateWorkspaces() {
getWorkspaces.running = true;
getActiveWorkspace.running = true;
}
function updateAll() {
updateWindowList();
updateMonitors();
updateLayers();
updateWorkspaces();
}
function biggestWindowForWorkspace(workspaceId) {
const windowsInThisWorkspace = HyprlandData.windowList.filter(w => w.workspace.id == workspaceId);
return windowsInThisWorkspace.reduce((maxWin, win) => {
const maxArea = (maxWin?.size?.[0] ?? 0) * (maxWin?.size?.[1] ?? 0);
const winArea = (win?.size?.[0] ?? 0) * (win?.size?.[1] ?? 0);
return winArea > maxArea ? win : maxWin;
}, null);
}
Component.onCompleted: {
updateAll();
}
Connections {
target: Hyprland
function onRawEvent(event) {
// console.log("Hyprland raw event:", event.name);
updateAll()
}
}
Process {
id: getClients
command: ["bash", "-c", "hyprctl clients -j | jq -c"]
stdout: SplitParser {
onRead: data => {
root.windowList = JSON.parse(data);
let tempWinByAddress = {};
for (var i = 0; i < root.windowList.length; ++i) {
var win = root.windowList[i];
tempWinByAddress[win.address] = win;
}
root.windowByAddress = tempWinByAddress;
root.addresses = root.windowList.map(win => win.address);
}
}
}
Process {
id: getMonitors
command: ["bash", "-c", "hyprctl monitors -j | jq -c"]
stdout: SplitParser {
onRead: data => {
root.monitors = JSON.parse(data);
}
}
}
Process {
id: getLayers
command: ["bash", "-c", "hyprctl layers -j | jq -c"]
stdout: SplitParser {
onRead: data => {
root.layers = JSON.parse(data);
}
}
}
Process {
id: getWorkspaces
command: ["bash", "-c", "hyprctl workspaces -j | jq -c"]
stdout: SplitParser {
onRead: data => {
root.workspaces = JSON.parse(data);
let tempWorkspaceById = {};
for (var i = 0; i < root.workspaces.length; ++i) {
var ws = root.workspaces[i];
tempWorkspaceById[ws.id] = ws;
}
root.workspaceById = tempWorkspaceById;
root.workspaceIds = root.workspaces.map(ws => ws.id);
}
}
}
Process {
id: getActiveWorkspace
command: ["bash", "-c", "hyprctl activeworkspace -j | jq -c"]
stdout: SplitParser {
onRead: data => {
root.activeWorkspace = JSON.parse(data);
}
}
}
}
@@ -1,93 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Io
import QtQuick
/**
* Simple polled network state service.
*/
Singleton {
id: root
property bool wifi: true
property bool ethernet: false
property int updateInterval: 1000
property string networkName: ""
property int networkStrength
property string materialSymbol: ethernet ? "lan" :
(Network.networkName.length > 0 && Network.networkName != "lo") ? (
Network.networkStrength > 80 ? "signal_wifi_4_bar" :
Network.networkStrength > 60 ? "network_wifi_3_bar" :
Network.networkStrength > 40 ? "network_wifi_2_bar" :
Network.networkStrength > 20 ? "network_wifi_1_bar" :
"signal_wifi_0_bar"
) : "signal_wifi_off"
function update() {
updateConnectionType.startCheck();
updateNetworkName.running = true;
updateNetworkStrength.running = true;
}
Timer {
interval: 10
running: true
repeat: true
onTriggered: {
root.update();
interval = root.updateInterval;
}
}
Process {
id: updateConnectionType
property string buffer
command: ["sh", "-c", "nmcli -t -f NAME,TYPE,DEVICE c show --active"]
running: true
function startCheck() {
buffer = "";
updateConnectionType.running = true;
}
stdout: SplitParser {
onRead: data => {
updateConnectionType.buffer += data + "\n";
}
}
onExited: (exitCode, exitStatus) => {
const lines = updateConnectionType.buffer.trim().split('\n');
let hasEthernet = false;
let hasWifi = false;
lines.forEach(line => {
if (line.includes("ethernet"))
hasEthernet = true;
else if (line.includes("wireless"))
hasWifi = true;
});
root.ethernet = hasEthernet;
root.wifi = hasWifi;
}
}
Process {
id: updateNetworkName
command: ["sh", "-c", "nmcli -t -f NAME c show --active | head -1"]
running: true
stdout: SplitParser {
onRead: data => {
root.networkName = data;
}
}
}
Process {
id: updateNetworkStrength
running: true
command: ["sh", "-c", "nmcli -f IN-USE,SIGNAL,SSID device wifi | awk '/^\*/{if (NR!=1) {print $2}}'"]
stdout: SplitParser {
onRead: data => {
root.networkStrength = parseInt(data);
}
}
}
}
@@ -1,62 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import qs.modules.common
import QtQuick
import Quickshell
import Quickshell.Io
/**
* Simple polled resource usage service with RAM, Swap, and CPU usage.
*/
Singleton {
property double memoryTotal: 1
property double memoryFree: 1
property double memoryUsed: memoryTotal - memoryFree
property double memoryUsedPercentage: memoryUsed / memoryTotal
property double swapTotal: 1
property double swapFree: 1
property double swapUsed: swapTotal - swapFree
property double swapUsedPercentage: swapTotal > 0 ? (swapUsed / swapTotal) : 0
property double cpuUsage: 0
property var previousCpuStats
Timer {
interval: 1
running: true
repeat: true
onTriggered: {
// Reload files
fileMeminfo.reload()
fileStat.reload()
// Parse memory and swap usage
const textMeminfo = fileMeminfo.text()
memoryTotal = Number(textMeminfo.match(/MemTotal: *(\d+)/)?.[1] ?? 1)
memoryFree = Number(textMeminfo.match(/MemAvailable: *(\d+)/)?.[1] ?? 0)
swapTotal = Number(textMeminfo.match(/SwapTotal: *(\d+)/)?.[1] ?? 1)
swapFree = Number(textMeminfo.match(/SwapFree: *(\d+)/)?.[1] ?? 0)
// Parse CPU usage
const textStat = fileStat.text()
const cpuLine = textStat.match(/^cpu\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/)
if (cpuLine) {
const stats = cpuLine.slice(1).map(Number)
const total = stats.reduce((a, b) => a + b, 0)
const idle = stats[3]
if (previousCpuStats) {
const totalDiff = total - previousCpuStats.total
const idleDiff = idle - previousCpuStats.idle
cpuUsage = totalDiff > 0 ? (1 - idleDiff / totalDiff) : 0
}
previousCpuStats = { total, idle }
}
interval = Config.options?.resources?.updateInterval ?? 3000
}
}
FileView { id: fileMeminfo; path: "/proc/meminfo" }
FileView { id: fileStat; path: "/proc/stat" }
}
-74
View File
@@ -1,74 +0,0 @@
//@ pragma UseQApplication
//@ pragma Env QS_NO_RELOAD_POPUP=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
// Adjust this to make the shell smaller or larger
//@ pragma Env QT_SCALE_FACTOR=1
import "./modules/common/"
import "./modules/background/"
import "./modules/bar/"
import "./modules/cheatsheet/"
import "./modules/dock/"
import "./modules/lock/"
import "./modules/mediaControls/"
import "./modules/notificationPopup/"
import "./modules/onScreenDisplay/"
import "./modules/onScreenKeyboard/"
import "./modules/overview/"
import "./modules/screenCorners/"
import "./modules/session/"
import "./modules/sidebarLeft/"
import "./modules/sidebarRight/"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Window
import Quickshell
import "./services/"
ShellRoot {
// Enable/disable modules here. False = not loaded at all, so rest assured
// no unnecessary stuff will take up memory if you decide to only use, say, the overview.
property bool enableBar: true
property bool enableBackground: true
property bool enableCheatsheet: true
property bool enableDock: true
property bool enableLock: true
property bool enableMediaControls: true
property bool enableNotificationPopup: true
property bool enableOnScreenDisplayBrightness: true
property bool enableOnScreenDisplayVolume: true
property bool enableOnScreenKeyboard: true
property bool enableOverview: true
property bool enableReloadPopup: true
property bool enableScreenCorners: true
property bool enableSession: true
property bool enableSidebarLeft: true
property bool enableSidebarRight: true
// Force initialization of some singletons
Component.onCompleted: {
MaterialThemeLoader.reapplyTheme()
Cliphist.refresh()
FirstRunExperience.load()
}
LazyLoader { active: enableBar; component: Bar {} }
LazyLoader { active: enableBackground; component: Background {} }
LazyLoader { active: enableCheatsheet; component: Cheatsheet {} }
LazyLoader { active: enableDock && Config.options.dock.enable; component: Dock {} }
LazyLoader { active: enableLock; component: Lock {} }
LazyLoader { active: enableMediaControls; component: MediaControls {} }
LazyLoader { active: enableNotificationPopup; component: NotificationPopup {} }
LazyLoader { active: enableOnScreenDisplayBrightness; component: OnScreenDisplayBrightness {} }
LazyLoader { active: enableOnScreenDisplayVolume; component: OnScreenDisplayVolume {} }
LazyLoader { active: enableOnScreenKeyboard; component: OnScreenKeyboard {} }
LazyLoader { active: enableOverview; component: Overview {} }
LazyLoader { active: enableReloadPopup; component: ReloadPopup {} }
LazyLoader { active: enableScreenCorners; component: ScreenCorners {} }
LazyLoader { active: enableSession; component: Session {} }
LazyLoader { active: enableSidebarLeft; component: SidebarLeft {} }
LazyLoader { active: enableSidebarRight; component: SidebarRight {} }
}
-29
View File
@@ -1,29 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import qs.modules.common.functions
import Qt.labs.platform
import QtQuick
import Quickshell
Singleton {
// XDG Dirs, with "file://"
readonly property string config: StandardPaths.standardLocations(StandardPaths.ConfigLocation)[0]
readonly property string state: StandardPaths.standardLocations(StandardPaths.StateLocation)[0]
readonly property string cache: StandardPaths.standardLocations(StandardPaths.CacheLocation)[0]
readonly property string pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
readonly property string downloads: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
// Other dirs used by the shell, without "file://"
property string assetsPath: Quickshell.shellPath("assets")
property string scriptPath: Quickshell.shellPath("scripts")
property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/quickshell`)
property string shellConfigName: "oo.json"
property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}`
property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`)
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`)
// Cleanup on init
Component.onCompleted: {
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`])
}
}
-38
View File
@@ -1,38 +0,0 @@
import qs
import qs.singletons
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
// Open states
property bool barOpen: true
property bool launcherOpen: true
// Smooth screen zoom
IpcHandler {
target: "zoom"
function zoomIn() {
screenZoom = Math.min(screenZoom + 0.4, 3.0)
}
function zoomOut() {
screenZoom = Math.max(screenZoom - 0.4, 1)
}
}
property real screenZoom: 1
onScreenZoomChanged: {
Quickshell.execDetached(["hyprctl", "keyword", "cursor:zoom_factor", root.screenZoom.toString()]);
}
Behavior on screenZoom {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
}
@@ -1,282 +0,0 @@
pragma ComponentBehavior: Bound
import qs
import qs.singletons
import qs.modules.common.widgets
import qs.modules.common.functions as CF
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: root
readonly property bool fixedClockPosition: Config.options.background.fixedClockPosition
readonly property real fixedClockX: Config.options.background.clockX
readonly property real fixedClockY: Config.options.background.clockY
Variants {
model: Quickshell.screens
PanelWindow {
id: bgRoot
required property var modelData
// Workspaces
property HyprlandMonitor monitor: Hyprland.monitorFor(modelData)
property list<var> relevantWindows: HyprlandData.windowList.filter(win => win.monitor == monitor.id && win.workspace.id >= 0).sort((a, b) => a.workspace.id - b.workspace.id)
property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1
property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10
// Wallpaper
property string wallpaperPath: Config.options.background.wallpaperPath
property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4")
|| Config.options.background.wallpaperPath.endsWith(".webm")
|| Config.options.background.wallpaperPath.endsWith(".mkv")
|| Config.options.background.wallpaperPath.endsWith(".avi")
|| Config.options.background.wallpaperPath.endsWith(".mov")
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
property int wallpaperWidth: modelData.width // Some reasonable init value, to be updated
property int wallpaperHeight: modelData.height // Some reasonable init value, to be updated
property real movableXSpace: (effectiveWallpaperScale - 1) / 2 * screen.width
property real movableYSpace: (effectiveWallpaperScale - 1) / 2 * screen.height
// Position
property real clockX: (modelData.width / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.width)
property real clockY: (modelData.height / 2) + ((Math.random() < 0.5 ? -1 : 1) * modelData.height)
property var textHorizontalAlignment: clockX < screen.width / 3 ? Text.AlignLeft :
(clockX > screen.width * 2 / 3 ? Text.AlignRight : Text.AlignHCenter)
// Colors
property color dominantColor: Appearance.colors.colPrimary
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
property color colText: CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12))
// Layer props
screen: modelData
exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: GlobalStates.screenLocked ? WlrLayer.Top : WlrLayer.Bottom
// WlrLayershell.layer: WlrLayer.Bottom
WlrLayershell.namespace: "quickshell:background"
anchors {
top: true
bottom: true
left: true
right: true
}
color: "transparent"
onWallpaperPathChanged: {
bgRoot.updateZoomScale()
// Clock position gets updated after zoom scale is updated
}
// Wallpaper zoom scale
function updateZoomScale() {
getWallpaperSizeProc.path = bgRoot.wallpaperPath
getWallpaperSizeProc.running = true;
}
Process {
id: getWallpaperSizeProc
property string path: bgRoot.wallpaperPath
command: [ "magick", "identify", "-format", "%w %h", path ]
stdout: StdioCollector {
id: wallpaperSizeOutputCollector
onStreamFinished: {
const output = wallpaperSizeOutputCollector.text
const [width, height] = output.split(" ").map(Number);
bgRoot.wallpaperWidth = width
bgRoot.wallpaperHeight = height
bgRoot.effectiveWallpaperScale = Math.max(1, Math.min(
bgRoot.preferredWallpaperScale,
width / bgRoot.screen.width,
height / bgRoot.screen.height
));
bgRoot.updateClockPosition()
}
}
}
// Clock positioning
function updateClockPosition() {
// Somehow all this manual setting is needed to make the proc correctly use the new values
leastBusyRegionProc.path = bgRoot.wallpaperPath
leastBusyRegionProc.contentWidth = clock.implicitWidth
leastBusyRegionProc.contentHeight = clock.implicitHeight
leastBusyRegionProc.horizontalPadding = (effectiveWallpaperScale - 1) / 2 * screen.width + 100
leastBusyRegionProc.verticalPadding = (effectiveWallpaperScale - 1) / 2 * screen.height + 100
leastBusyRegionProc.running = false;
leastBusyRegionProc.running = true;
}
Process {
id: leastBusyRegionProc
property string path: bgRoot.wallpaperPath
property int contentWidth: 300
property int contentHeight: 300
property int horizontalPadding: bgRoot.movableXSpace
property int verticalPadding: bgRoot.movableYSpace
command: [Quickshell.shellPath("scripts/images/least_busy_region.py"),
"--screen-width", bgRoot.screen.width,
"--screen-height", bgRoot.screen.height,
"--width", contentWidth,
"--height", contentHeight,
"--horizontal-padding", horizontalPadding,
"--vertical-padding", verticalPadding,
path
]
stdout: StdioCollector {
id: leastBusyRegionOutputCollector
onStreamFinished: {
const output = leastBusyRegionOutputCollector.text
// console.log("[Background] Least busy region output:", output)
if (output.length === 0) return;
const parsedContent = JSON.parse(output)
bgRoot.clockX = parsedContent.center_x
bgRoot.clockY = parsedContent.center_y
bgRoot.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary
}
}
}
// Wallpaper
Image {
visible: !bgRoot.wallpaperIsVideo
property real value // 0 to 1, for offset
value: {
// Range = half-groups that workspaces span on
const chunkSize = 5;
const lower = Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize;
const upper = Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize;
const range = upper - lower;
return (Config.options.background.parallax.enableWorkspace ? ((bgRoot.monitor.activeWorkspace.id - lower) / range) : 0.5)
+ (0.15 * GlobalStates.sidebarRightOpen * Config.options.background.parallax.enableSidebar)
- (0.15 * GlobalStates.sidebarLeftOpen * Config.options.background.parallax.enableSidebar)
}
property real effectiveValue: Math.max(0, Math.min(1, value))
x: -(bgRoot.movableXSpace) - (effectiveValue - 0.5) * 2 * bgRoot.movableXSpace
y: -(bgRoot.movableYSpace)
source: bgRoot.wallpaperPath
fillMode: Image.PreserveAspectCrop
Behavior on x {
NumberAnimation {
duration: 600
easing.type: Easing.OutCubic
}
}
sourceSize {
width: bgRoot.screen.width * bgRoot.effectiveWallpaperScale
height: bgRoot.screen.height * bgRoot.effectiveWallpaperScale
}
// The clock
Item {
id: clock
anchors {
left: parent.left
top: parent.top
leftMargin: ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2)
topMargin: ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2)
Behavior on leftMargin {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
Behavior on topMargin {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
implicitWidth: clockColumn.implicitWidth
implicitHeight: clockColumn.implicitHeight
ColumnLayout {
id: clockColumn
anchors.centerIn: parent
spacing: 0
StyledText {
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 90
weight: Font.Bold
}
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
text: DateTime.time
}
StyledText {
Layout.fillWidth: true
Layout.topMargin: -5
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 20
weight: Font.DemiBold
}
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
text: DateTime.date
}
}
RowLayout {
anchors {
top: clockColumn.bottom
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
topMargin: 5
leftMargin: -5
rightMargin: -5
}
opacity: GlobalStates.screenLocked ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 }
MaterialSymbol {
text: "lock"
Layout.fillWidth: false
iconSize: Appearance.font.pixelSize.huge
color: bgRoot.colText
}
StyledText {
Layout.fillWidth: false
text: "Locked"
color: bgRoot.colText
font {
pixelSize: Appearance.font.pixelSize.larger
}
}
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 }
}
}
}
// Password prompt
StyledText {
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 30
}
opacity: (GlobalStates.screenLocked && !GlobalStates.screenLockContainsCharacters) ? 1 : 0
scale: opacity
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
text: "Enter password"
color: CF.ColorUtils.transparentize(bgRoot.colText, 0.3)
font {
pixelSize: Appearance.font.pixelSize.normal
}
}
}
}
}
-161
View File
@@ -1,161 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import qs
import qs.singletons
import qs.modules.common.widgets
Scope {
id: root
Variants {
// For each monitor
model: Quickshell.screens
LazyLoader {
id: barLoader
active: GlobalStates.barOpen
required property ShellScreen modelData
component: PanelWindow { // Bar window
id: barRoot
screen: barLoader.modelData
exclusionMode: ExclusionMode.Ignore
exclusiveZone: Appearance.sizes.barHeight + Appearance.sizes.barBorder
WlrLayershell.namespace: "oo:bar"
implicitHeight: Appearance.sizes.barHeight + Appearance.sizes.barBorder
mask: Region {
item: barContent
}
color: "transparent"
anchors {
bottom: true
left: true
right: true
}
Item { // Bar content region
id: barContent
anchors {
right: parent.right
left: parent.left
bottom: parent.bottom
}
implicitHeight: Appearance.sizes.barHeight + Appearance.sizes.barBorder
// Background
Rectangle {
id: barBackground
anchors {
fill: parent
topMargin: Appearance.sizes.barBorder
}
color: Appearance.colors.colLayer0
}
// Border
Rectangle {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: Appearance.sizes.barHeight
}
implicitHeight: Appearance.sizes.barBorder
color: Appearance.colors.colOutlineVariant
}
// Stuff
RowLayout {
anchors {
fill: parent
topMargin: Appearance.sizes.barBorder
}
BarButton {
id: startButton
Layout.fillHeight: true
property real targetRotation: 0
onPressed: targetRotation += 180
rotation: targetRotation
Behavior on rotation {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
onClicked: GlobalStates.launcherOpen = !GlobalStates.launcherOpen
HexRect {
anchors.centerIn: parent
color: startButton.active ?
(startButton.hovered ? Appearance.colors.colPrimaryHover : Appearance.colors.colPrimary)
: (startButton.hovered ? Appearance.colors.colLayer3Hover : Appearance.colors.colLayer3)
Behavior on borderColor {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
property real size: Appearance.sizes.barHeight * 0.75
property real sizeDown: size * 0.85
property real effectiveSize: startButton.down ? sizeDown : size
Behavior on effectiveSize {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
implicitWidth: effectiveSize
implicitHeight: effectiveSize
}
contentItem: MaterialSymbol {
anchors.centerIn: parent
text: "add"
iconSize: Appearance.sizes.barHeight * 0.6
color: Appearance.colors.colOnLayer3
}
}
}
}
}
}
}
IpcHandler {
target: "bar"
function toggle(): void {
GlobalStates.barOpen = !GlobalStates.barOpen;
}
function close(): void {
GlobalStates.barOpen = false;
}
function open(): void {
GlobalStates.barOpen = true;
}
}
GlobalShortcut {
name: "barToggle"
description: "Toggles bar on press"
onPressed: {
GlobalStates.barOpen = !GlobalStates.barOpen;
}
}
GlobalShortcut {
name: "barOpen"
description: "Opens bar on press"
onPressed: {
GlobalStates.barOpen = true;
}
}
GlobalShortcut {
name: "barClose"
description: "Closes bar on press"
onPressed: {
GlobalStates.barOpen = false;
}
}
}
@@ -1,11 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.singletons
Button {
implicitHeight: Appearance.sizes.barHeight
implicitWidth: Appearance.sizes.barHeight
background: null
contentItem: null
}
@@ -1,41 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
id: root
/**
* Trims the File protocol off the input string
* @param {string} str
* @returns {string}
*/
function trimFileProtocol(str) {
return str.startsWith("file://") ? str.slice(7) : str;
}
/**
* Extracts the file name from a file path
* @param {string} str
* @returns {string}
*/
function fileNameForPath(str) {
if (typeof str !== "string") return "";
const trimmed = trimFileProtocol(str);
return trimmed.split(/[\\/]/).pop();
}
/**
* Removes the file extension from a file path or name
* @param {string} str
* @returns {string}
*/
function trimFileExt(str) {
if (typeof str !== "string") return "";
const trimmed = trimFileProtocol(str);
const lastDot = trimmed.lastIndexOf(".");
if (lastDot > -1 && lastDot > trimmed.lastIndexOf("/")) {
return trimmed.slice(0, lastDot);
}
return trimmed;
}
}
@@ -1,98 +0,0 @@
pragma Singleton
import Quickshell
Singleton {
id: root
function toPlainObject(qtObj) {
if (qtObj === null || typeof qtObj !== "object") return qtObj;
// Handle true arrays
if (Array.isArray(qtObj)) {
return qtObj.map(item => toPlainObject(item));
}
// Handle array-like Qt objects (e.g., have length and numeric keys)
if (
typeof qtObj.length === "number" &&
qtObj.length > 0 &&
Object.keys(qtObj).every(
key => !isNaN(key) || key === "length"
)
) {
let arr = [];
for (let i = 0; i < qtObj.length; i++) {
arr.push(toPlainObject(qtObj[i]));
}
return arr;
}
const result = ({});
for (let key in qtObj) {
if (
typeof qtObj[key] !== "function" &&
!key.startsWith("objectName") &&
!key.startsWith("children") &&
!key.startsWith("object") &&
!key.startsWith("parent") &&
!key.startsWith("metaObject") &&
!key.startsWith("destroyed") &&
!key.startsWith("reloadableId")
) {
result[key] = toPlainObject(qtObj[key]);
}
}
// console.log(JSON.stringify(result))
return result;
}
function applyToQtObject(qtObj, jsonObj) {
// console.log("applyToQtObject", JSON.stringify(qtObj, null, 2), "<<", JSON.stringify(jsonObj, null, 2));
if (!qtObj || typeof jsonObj !== "object" || jsonObj === null) return;
// Detect array-like Qt objects
const isQtArrayLike = obj => {
return obj && typeof obj === "object" &&
typeof obj.length === "number" &&
obj.length > 0 &&
Object.keys(obj).every(key => !isNaN(key) || key === "length");
};
// If both are arrays or array-like, update in place or replace
if ((Array.isArray(qtObj) || isQtArrayLike(qtObj)) && Array.isArray(jsonObj)) {
qtObj.length = 0;
for (let i = 0; i < jsonObj.length; i++) {
qtObj.push(jsonObj[i]);
}
return;
}
// If target is array or array-like but source is not, clear
if ((Array.isArray(qtObj) || isQtArrayLike(qtObj)) && !Array.isArray(jsonObj)) {
qtObj.length = 0;
return;
}
// If source is array but target is not, assign directly if possible
if (!(Array.isArray(qtObj) || isQtArrayLike(qtObj)) && Array.isArray(jsonObj)) {
return jsonObj;
}
for (let key in jsonObj) {
if (!qtObj.hasOwnProperty(key)) continue;
const value = qtObj[key];
const jsonValue = jsonObj[key];
// console.log("applying to qt obj key:", value, "jsonValue:", jsonValue);
if ((Array.isArray(value) || isQtArrayLike(value)) && Array.isArray(jsonValue)) {
value.length = 0;
for (let i = 0; i < jsonValue.length; i++) {
value.push(jsonValue[i]);
}
} else if (value && typeof value === "object" && !Array.isArray(value) && !isQtArrayLike(value)) {
applyToQtObject(value, jsonValue);
} else {
qtObj[key] = jsonValue;
}
}
}
}
@@ -1,682 +0,0 @@
.pragma library
// https://github.com/farzher/fuzzysort
// License: MIT | Copyright (c) 2018 Stephen Kamenar
// A copy of the license is available in the `licenses` folder of this repository
var single = (search, target) => {
if(!search || !target) return NULL
var preparedSearch = getPreparedSearch(search)
if(!isPrepared(target)) target = getPrepared(target)
var searchBitflags = preparedSearch.bitflags
if((searchBitflags & target._bitflags) !== searchBitflags) return NULL
return algorithm(preparedSearch, target)
}
var go = (search, targets, options) => {
if(!search) return options?.all ? all(targets, options) : noResults
var preparedSearch = getPreparedSearch(search)
var searchBitflags = preparedSearch.bitflags
var containsSpace = preparedSearch.containsSpace
var threshold = denormalizeScore( options?.threshold || 0 )
var limit = options?.limit || INFINITY
var resultsLen = 0; var limitedCount = 0
var targetsLen = targets.length
function push_result(result) {
if(resultsLen < limit) { q.add(result); ++resultsLen }
else {
++limitedCount
if(result._score > q.peek()._score) q.replaceTop(result)
}
}
// This code is copy/pasted 3 times for performance reasons [options.key, options.keys, no keys]
// options.key
if(options?.key) {
var key = options.key
for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]
var target = getValue(obj, key)
if(!target) continue
if(!isPrepared(target)) target = getPrepared(target)
if((searchBitflags & target._bitflags) !== searchBitflags) continue
var result = algorithm(preparedSearch, target)
if(result === NULL) continue
if(result._score < threshold) continue
result.obj = obj
push_result(result)
}
// options.keys
} else if(options?.keys) {
var keys = options.keys
var keysLen = keys.length
outer: for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]
{ // early out based on bitflags
var keysBitflags = 0
for (var keyI = 0; keyI < keysLen; ++keyI) {
var key = keys[keyI]
var target = getValue(obj, key)
if(!target) { tmpTargets[keyI] = noTarget; continue }
if(!isPrepared(target)) target = getPrepared(target)
tmpTargets[keyI] = target
keysBitflags |= target._bitflags
}
if((searchBitflags & keysBitflags) !== searchBitflags) continue
}
if(containsSpace) for(let i=0; i<preparedSearch.spaceSearches.length; i++) keysSpacesBestScores[i] = NEGATIVE_INFINITY
for (var keyI = 0; keyI < keysLen; ++keyI) {
target = tmpTargets[keyI]
if(target === noTarget) { tmpResults[keyI] = noTarget; continue }
tmpResults[keyI] = algorithm(preparedSearch, target, /*allowSpaces=*/false, /*allowPartialMatch=*/containsSpace)
if(tmpResults[keyI] === NULL) { tmpResults[keyI] = noTarget; continue }
// todo: this seems weird and wrong. like what if our first match wasn't good. this should just replace it instead of averaging with it
// if our second match isn't good we ignore it instead of averaging with it
if(containsSpace) for(let i=0; i<preparedSearch.spaceSearches.length; i++) {
if(allowPartialMatchScores[i] > -1000) {
if(keysSpacesBestScores[i] > NEGATIVE_INFINITY) {
var tmp = (keysSpacesBestScores[i] + allowPartialMatchScores[i]) / 4/*bonus score for having multiple matches*/
if(tmp > keysSpacesBestScores[i]) keysSpacesBestScores[i] = tmp
}
}
if(allowPartialMatchScores[i] > keysSpacesBestScores[i]) keysSpacesBestScores[i] = allowPartialMatchScores[i]
}
}
if(containsSpace) {
for(let i=0; i<preparedSearch.spaceSearches.length; i++) { if(keysSpacesBestScores[i] === NEGATIVE_INFINITY) continue outer }
} else {
var hasAtLeast1Match = false
for(let i=0; i < keysLen; i++) { if(tmpResults[i]._score !== NEGATIVE_INFINITY) { hasAtLeast1Match = true; break } }
if(!hasAtLeast1Match) continue
}
var objResults = new KeysResult(keysLen)
for(let i=0; i < keysLen; i++) { objResults[i] = tmpResults[i] }
if(containsSpace) {
var score = 0
for(let i=0; i<preparedSearch.spaceSearches.length; i++) score += keysSpacesBestScores[i]
} else {
// todo could rewrite this scoring to be more similar to when there's spaces
// if we match multiple keys give us bonus points
var score = NEGATIVE_INFINITY
for(let i=0; i<keysLen; i++) {
var result = objResults[i]
if(result._score > -1000) {
if(score > NEGATIVE_INFINITY) {
var tmp = (score + result._score) / 4/*bonus score for having multiple matches*/
if(tmp > score) score = tmp
}
}
if(result._score > score) score = result._score
}
}
objResults.obj = obj
objResults._score = score
if(options?.scoreFn) {
score = options.scoreFn(objResults)
if(!score) continue
score = denormalizeScore(score)
objResults._score = score
}
if(score < threshold) continue
push_result(objResults)
}
// no keys
} else {
for(var i = 0; i < targetsLen; ++i) { var target = targets[i]
if(!target) continue
if(!isPrepared(target)) target = getPrepared(target)
if((searchBitflags & target._bitflags) !== searchBitflags) continue
var result = algorithm(preparedSearch, target)
if(result === NULL) continue
if(result._score < threshold) continue
push_result(result)
}
}
if(resultsLen === 0) return noResults
var results = new Array(resultsLen)
for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll()
results.total = resultsLen + limitedCount
return results
}
// this is written as 1 function instead of 2 for minification. perf seems fine ...
// except when minified. the perf is very slow
var highlight = (result, open='<b>', close='</b>') => {
var callback = typeof open === 'function' ? open : undefined
var target = result.target
var targetLen = target.length
var indexes = result.indexes
var highlighted = ''
var matchI = 0
var indexesI = 0
var opened = false
var parts = []
for(var i = 0; i < targetLen; ++i) { var char = target[i]
if(indexes[indexesI] === i) {
++indexesI
if(!opened) { opened = true
if(callback) {
parts.push(highlighted); highlighted = ''
} else {
highlighted += open
}
}
if(indexesI === indexes.length) {
if(callback) {
highlighted += char
parts.push(callback(highlighted, matchI++)); highlighted = ''
parts.push(target.substr(i+1))
} else {
highlighted += char + close + target.substr(i+1)
}
break
}
} else {
if(opened) { opened = false
if(callback) {
parts.push(callback(highlighted, matchI++)); highlighted = ''
} else {
highlighted += close
}
}
}
highlighted += char
}
return callback ? parts : highlighted
}
var prepare = (target) => {
if(typeof target === 'number') target = ''+target
else if(typeof target !== 'string') target = ''
var info = prepareLowerInfo(target)
return new_result(target, {_targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _bitflags:info.bitflags})
}
var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear() }
// Below this point is only internal code
// Below this point is only internal code
// Below this point is only internal code
// Below this point is only internal code
class Result {
get ['indexes']() { return this._indexes.slice(0, this._indexes.len).sort((a,b)=>a-b) }
set ['indexes'](indexes) { return this._indexes = indexes }
['highlight'](open, close) { return highlight(this, open, close) }
get ['score']() { return normalizeScore(this._score) }
set ['score'](score) { this._score = denormalizeScore(score) }
}
class KeysResult extends Array {
get ['score']() { return normalizeScore(this._score) }
set ['score'](score) { this._score = denormalizeScore(score) }
}
var new_result = (target, options) => {
const result = new Result()
result['target'] = target
result['obj'] = options.obj ?? NULL
result._score = options._score ?? NEGATIVE_INFINITY
result._indexes = options._indexes ?? []
result._targetLower = options._targetLower ?? ''
result._targetLowerCodes = options._targetLowerCodes ?? NULL
result._nextBeginningIndexes = options._nextBeginningIndexes ?? NULL
result._bitflags = options._bitflags ?? 0
return result
}
var normalizeScore = score => {
if(score === NEGATIVE_INFINITY) return 0
if(score > 1) return score
return Math.E ** ( ((-score + 1)**.04307 - 1) * -2)
}
var denormalizeScore = normalizedScore => {
if(normalizedScore === 0) return NEGATIVE_INFINITY
if(normalizedScore > 1) return normalizedScore
return 1 - Math.pow((Math.log(normalizedScore) / -2 + 1), 1 / 0.04307)
}
var prepareSearch = (search) => {
if(typeof search === 'number') search = ''+search
else if(typeof search !== 'string') search = ''
search = search.trim()
var info = prepareLowerInfo(search)
var spaceSearches = []
if(info.containsSpace) {
var searches = search.split(/\s+/)
searches = [...new Set(searches)] // distinct
for(var i=0; i<searches.length; i++) {
if(searches[i] === '') continue
var _info = prepareLowerInfo(searches[i])
spaceSearches.push({lowerCodes:_info.lowerCodes, _lower:searches[i].toLowerCase(), containsSpace:false})
}
}
return {lowerCodes: info.lowerCodes, _lower: info._lower, containsSpace: info.containsSpace, bitflags: info.bitflags, spaceSearches: spaceSearches}
}
var getPrepared = (target) => {
if(target.length > 999) return prepare(target) // don't cache huge targets
var targetPrepared = preparedCache.get(target)
if(targetPrepared !== undefined) return targetPrepared
targetPrepared = prepare(target)
preparedCache.set(target, targetPrepared)
return targetPrepared
}
var getPreparedSearch = (search) => {
if(search.length > 999) return prepareSearch(search) // don't cache huge searches
var searchPrepared = preparedSearchCache.get(search)
if(searchPrepared !== undefined) return searchPrepared
searchPrepared = prepareSearch(search)
preparedSearchCache.set(search, searchPrepared)
return searchPrepared
}
var all = (targets, options) => {
var results = []; results.total = targets.length // this total can be wrong if some targets are skipped
var limit = options?.limit || INFINITY
if(options?.key) {
for(var i=0;i<targets.length;i++) { var obj = targets[i]
var target = getValue(obj, options.key)
if(target == NULL) continue
if(!isPrepared(target)) target = getPrepared(target)
var result = new_result(target.target, {_score: target._score, obj: obj})
results.push(result); if(results.length >= limit) return results
}
} else if(options?.keys) {
for(var i=0;i<targets.length;i++) { var obj = targets[i]
var objResults = new KeysResult(options.keys.length)
for (var keyI = options.keys.length - 1; keyI >= 0; --keyI) {
var target = getValue(obj, options.keys[keyI])
if(!target) { objResults[keyI] = noTarget; continue }
if(!isPrepared(target)) target = getPrepared(target)
target._score = NEGATIVE_INFINITY
target._indexes.len = 0
objResults[keyI] = target
}
objResults.obj = obj
objResults._score = NEGATIVE_INFINITY
results.push(objResults); if(results.length >= limit) return results
}
} else {
for(var i=0;i<targets.length;i++) { var target = targets[i]
if(target == NULL) continue
if(!isPrepared(target)) target = getPrepared(target)
target._score = NEGATIVE_INFINITY
target._indexes.len = 0
results.push(target); if(results.length >= limit) return results
}
}
return results
}
var algorithm = (preparedSearch, prepared, allowSpaces=false, allowPartialMatch=false) => {
if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared, allowPartialMatch)
var searchLower = preparedSearch._lower
var searchLowerCodes = preparedSearch.lowerCodes
var searchLowerCode = searchLowerCodes[0]
var targetLowerCodes = prepared._targetLowerCodes
var searchLen = searchLowerCodes.length
var targetLen = targetLowerCodes.length
var searchI = 0 // where we at
var targetI = 0 // where you at
var matchesSimpleLen = 0
// very basic fuzzy match; to remove non-matching targets ASAP!
// walk through target. find sequential matches.
// if all chars aren't found then exit
for(;;) {
var isMatch = searchLowerCode === targetLowerCodes[targetI]
if(isMatch) {
matchesSimple[matchesSimpleLen++] = targetI
++searchI; if(searchI === searchLen) break
searchLowerCode = searchLowerCodes[searchI]
}
++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI
}
var searchI = 0
var successStrict = false
var matchesStrictLen = 0
var nextBeginningIndexes = prepared._nextBeginningIndexes
if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target)
targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1]
// Our target string successfully matched all characters in sequence!
// Let's try a more advanced and strict test to improve the score
// only count it as a match if it's consecutive or a beginning character!
var backtrackCount = 0
if(targetI !== targetLen) for(;;) {
if(targetI >= targetLen) {
// We failed to find a good spot for this search char, go back to the previous search char and force it forward
if(searchI <= 0) break // We failed to push chars forward for a better match
++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match
--searchI
var lastMatch = matchesStrict[--matchesStrictLen]
targetI = nextBeginningIndexes[lastMatch]
} else {
var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI]
if(isMatch) {
matchesStrict[matchesStrictLen++] = targetI
++searchI; if(searchI === searchLen) { successStrict = true; break }
++targetI
} else {
targetI = nextBeginningIndexes[targetI]
}
}
}
// check if it's a substring match
var substringIndex = searchLen <= 1 ? -1 : prepared._targetLower.indexOf(searchLower, matchesSimple[0]) // perf: this is slow
var isSubstring = !!~substringIndex
var isSubstringBeginning = !isSubstring ? false : substringIndex===0 || prepared._nextBeginningIndexes[substringIndex-1] === substringIndex
// if it's a substring match but not at a beginning index, let's try to find a substring starting at a beginning index for a better score
if(isSubstring && !isSubstringBeginning) {
for(var i=0; i<nextBeginningIndexes.length; i=nextBeginningIndexes[i]) {
if(i <= substringIndex) continue
for(var s=0; s<searchLen; s++) if(searchLowerCodes[s] !== prepared._targetLowerCodes[i+s]) break
if(s === searchLen) { substringIndex = i; isSubstringBeginning = true; break }
}
}
// tally up the score & keep track of matches for highlighting later
// if it's a simple match, we'll switch to a substring match if a substring exists
// if it's a strict match, we'll switch to a substring match only if that's a better score
var calculateScore = matches => {
var score = 0
var extraMatchGroupCount = 0
for(var i = 1; i < searchLen; ++i) {
if(matches[i] - matches[i-1] !== 1) {score -= matches[i]; ++extraMatchGroupCount}
}
var unmatchedDistance = matches[searchLen-1] - matches[0] - (searchLen-1)
score -= (12+unmatchedDistance) * extraMatchGroupCount // penality for more groups
if(matches[0] !== 0) score -= matches[0]*matches[0]*.2 // penality for not starting near the beginning
if(!successStrict) {
score *= 1000
} else {
// successStrict on a target with too many beginning indexes loses points for being a bad target
var uniqueBeginningIndexes = 1
for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes
if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10 // quite arbitrary numbers here ...
}
score -= (targetLen - searchLen)/2 // penality for longer targets
if(isSubstring) score /= 1+searchLen*searchLen*1 // bonus for being a full substring
if(isSubstringBeginning) score /= 1+searchLen*searchLen*1 // bonus for substring starting on a beginningIndex
score -= (targetLen - searchLen)/2 // penality for longer targets
return score
}
if(!successStrict) {
if(isSubstring) for(var i=0; i<searchLen; ++i) matchesSimple[i] = substringIndex+i // at this point it's safe to overwrite matchehsSimple with substr matches
var matchesBest = matchesSimple
var score = calculateScore(matchesBest)
} else {
if(isSubstringBeginning) {
for(var i=0; i<searchLen; ++i) matchesSimple[i] = substringIndex+i // at this point it's safe to overwrite matchehsSimple with substr matches
var matchesBest = matchesSimple
var score = calculateScore(matchesSimple)
} else {
var matchesBest = matchesStrict
var score = calculateScore(matchesStrict)
}
}
prepared._score = score
for(var i = 0; i < searchLen; ++i) prepared._indexes[i] = matchesBest[i]
prepared._indexes.len = searchLen
const result = new Result()
result.target = prepared.target
result._score = prepared._score
result._indexes = prepared._indexes
return result
}
var algorithmSpaces = (preparedSearch, target, allowPartialMatch) => {
var seen_indexes = new Set()
var score = 0
var result = NULL
var first_seen_index_last_search = 0
var searches = preparedSearch.spaceSearches
var searchesLen = searches.length
var changeslen = 0
// Return _nextBeginningIndexes back to its normal state
var resetNextBeginningIndexes = () => {
for(let i=changeslen-1; i>=0; i--) target._nextBeginningIndexes[nextBeginningIndexesChanges[i*2 + 0]] = nextBeginningIndexesChanges[i*2 + 1]
}
var hasAtLeast1Match = false
for(var i=0; i<searchesLen; ++i) {
allowPartialMatchScores[i] = NEGATIVE_INFINITY
var search = searches[i]
result = algorithm(search, target)
if(allowPartialMatch) {
if(result === NULL) continue
hasAtLeast1Match = true
} else {
if(result === NULL) {resetNextBeginningIndexes(); return NULL}
}
// if not the last search, we need to mutate _nextBeginningIndexes for the next search
var isTheLastSearch = i === searchesLen - 1
if(!isTheLastSearch) {
var indexes = result._indexes
var indexesIsConsecutiveSubstring = true
for(let i=0; i<indexes.len-1; i++) {
if(indexes[i+1] - indexes[i] !== 1) {
indexesIsConsecutiveSubstring = false; break;
}
}
if(indexesIsConsecutiveSubstring) {
var newBeginningIndex = indexes[indexes.len-1] + 1
var toReplace = target._nextBeginningIndexes[newBeginningIndex-1]
for(let i=newBeginningIndex-1; i>=0; i--) {
if(toReplace !== target._nextBeginningIndexes[i]) break
target._nextBeginningIndexes[i] = newBeginningIndex
nextBeginningIndexesChanges[changeslen*2 + 0] = i
nextBeginningIndexesChanges[changeslen*2 + 1] = toReplace
changeslen++
}
}
}
score += result._score / searchesLen
allowPartialMatchScores[i] = result._score / searchesLen
// dock points based on order otherwise "c man" returns Manifest.cpp instead of CheatManager.h
if(result._indexes[0] < first_seen_index_last_search) {
score -= (first_seen_index_last_search - result._indexes[0]) * 2
}
first_seen_index_last_search = result._indexes[0]
for(var j=0; j<result._indexes.len; ++j) seen_indexes.add(result._indexes[j])
}
if(allowPartialMatch && !hasAtLeast1Match) return NULL
resetNextBeginningIndexes()
// allows a search with spaces that's an exact substring to score well
var allowSpacesResult = algorithm(preparedSearch, target, /*allowSpaces=*/true)
if(allowSpacesResult !== NULL && allowSpacesResult._score > score) {
if(allowPartialMatch) {
for(var i=0; i<searchesLen; ++i) {
allowPartialMatchScores[i] = allowSpacesResult._score / searchesLen
}
}
return allowSpacesResult
}
if(allowPartialMatch) result = target
result._score = score
var i = 0
for (let index of seen_indexes) result._indexes[i++] = index
result._indexes.len = i
return result
}
// we use this instead of just .normalize('NFD').replace(/[\u0300-\u036f]/g, '') because that screws with japanese characters
var remove_accents = (str) => str.replace(/\p{Script=Latin}+/gu, match => match.normalize('NFD')).replace(/[\u0300-\u036f]/g, '')
var prepareLowerInfo = (str) => {
str = remove_accents(str)
var strLen = str.length
var lower = str.toLowerCase()
var lowerCodes = [] // new Array(strLen) sparse array is too slow
var bitflags = 0
var containsSpace = false // space isn't stored in bitflags because of how searching with a space works
for(var i = 0; i < strLen; ++i) {
var lowerCode = lowerCodes[i] = lower.charCodeAt(i)
if(lowerCode === 32) {
containsSpace = true
continue // it's important that we don't set any bitflags for space
}
var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet
: lowerCode>=48&&lowerCode<=57 ? 26 // numbers
// 3 bits available
: lowerCode<=127 ? 30 // other ascii
: 31 // other utf8
bitflags |= 1<<bit
}
return {lowerCodes:lowerCodes, bitflags:bitflags, containsSpace:containsSpace, _lower:lower}
}
var prepareBeginningIndexes = (target) => {
var targetLen = target.length
var beginningIndexes = []; var beginningIndexesLen = 0
var wasUpper = false
var wasAlphanum = false
for(var i = 0; i < targetLen; ++i) {
var targetCode = target.charCodeAt(i)
var isUpper = targetCode>=65&&targetCode<=90
var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum
wasUpper = isUpper
wasAlphanum = isAlphanum
if(isBeginning) beginningIndexes[beginningIndexesLen++] = i
}
return beginningIndexes
}
var prepareNextBeginningIndexes = (target) => {
target = remove_accents(target)
var targetLen = target.length
var beginningIndexes = prepareBeginningIndexes(target)
var nextBeginningIndexes = [] // new Array(targetLen) sparse array is too slow
var lastIsBeginning = beginningIndexes[0]
var lastIsBeginningI = 0
for(var i = 0; i < targetLen; ++i) {
if(lastIsBeginning > i) {
nextBeginningIndexes[i] = lastIsBeginning
} else {
lastIsBeginning = beginningIndexes[++lastIsBeginningI]
nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning
}
}
return nextBeginningIndexes
}
var preparedCache = new Map()
var preparedSearchCache = new Map()
// the theory behind these being globals is to reduce garbage collection by not making new arrays
var matchesSimple = []; var matchesStrict = []
var nextBeginningIndexesChanges = [] // allows straw berry to match strawberry well, by modifying the end of a substring to be considered a beginning index for the rest of the search
var keysSpacesBestScores = []; var allowPartialMatchScores = []
var tmpTargets = []; var tmpResults = []
// prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop]
// prop = 'key1.key2' 10ms
// prop = ['key1', 'key2'] 27ms
// prop = obj => obj.tags.join() ??ms
var getValue = (obj, prop) => {
var tmp = obj[prop]; if(tmp !== undefined) return tmp
if(typeof prop === 'function') return prop(obj) // this should run first. but that makes string props slower
var segs = prop
if(!Array.isArray(prop)) segs = prop.split('.')
var len = segs.length
var i = -1
while (obj && (++i < len)) obj = obj[segs[i]]
return obj
}
var isPrepared = (x) => { return typeof x === 'object' && typeof x._bitflags === 'number' }
var INFINITY = Infinity; var NEGATIVE_INFINITY = -INFINITY
var noResults = []; noResults.total = 0
var NULL = null
var noTarget = prepare('')
// Hacked version of https://github.com/lemire/FastPriorityQueue.js
var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c<o;){var s=c+1;a=c,s<o&&e[s]._score<e[c]._score&&(a=s),e[a-1>>1]=e[a],c=1+(a<<1)}for(var f=a-1>>1;a>0&&v._score<e[f]._score;f=(a=f)-1>>1)e[a]=e[f];e[a]=v};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r._score<e[v]._score;v=(a=v)-1>>1)e[a]=e[v];e[a]=r}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v()}),a}
var q = fastpriorityqueue() // reuse this
@@ -1,141 +0,0 @@
// Original code from https://github.com/koeqaife/hyprland-material-you
// Original code license: GPLv3
// Translated to Js from Cython with an LLM and reviewed
function min3(a, b, c) {
return a < b && a < c ? a : b < c ? b : c;
}
function max3(a, b, c) {
return a > b && a > c ? a : b > c ? b : c;
}
function min2(a, b) {
return a < b ? a : b;
}
function max2(a, b) {
return a > b ? a : b;
}
function levenshteinDistance(s1, s2) {
let len1 = s1.length;
let len2 = s2.length;
if (len1 === 0) return len2;
if (len2 === 0) return len1;
if (len2 > len1) {
[s1, s2] = [s2, s1];
[len1, len2] = [len2, len1];
}
let prev = new Array(len2 + 1);
let curr = new Array(len2 + 1);
for (let j = 0; j <= len2; j++) {
prev[j] = j;
}
for (let i = 1; i <= len1; i++) {
curr[0] = i;
for (let j = 1; j <= len2; j++) {
let cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
curr[j] = min3(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
}
[prev, curr] = [curr, prev];
}
return prev[len2];
}
function partialRatio(shortS, longS) {
let lenS = shortS.length;
let lenL = longS.length;
let best = 0.0;
if (lenS === 0) return 1.0;
for (let i = 0; i <= lenL - lenS; i++) {
let sub = longS.slice(i, i + lenS);
let dist = levenshteinDistance(shortS, sub);
let score = 1.0 - (dist / lenS);
if (score > best) best = score;
}
return best;
}
function computeScore(s1, s2) {
if (s1 === s2) return 1.0;
let dist = levenshteinDistance(s1, s2);
let maxLen = max2(s1.length, s2.length);
if (maxLen === 0) return 1.0;
let full = 1.0 - (dist / maxLen);
let part = s1.length < s2.length ? partialRatio(s1, s2) : partialRatio(s2, s1);
let score = 0.85 * full + 0.15 * part;
if (s1 && s2 && s1[0] !== s2[0]) {
score -= 0.05;
}
let lenDiff = Math.abs(s1.length - s2.length);
if (lenDiff >= 3) {
score -= 0.05 * lenDiff / maxLen;
}
let commonPrefixLen = 0;
let minLen = min2(s1.length, s2.length);
for (let i = 0; i < minLen; i++) {
if (s1[i] === s2[i]) {
commonPrefixLen++;
} else {
break;
}
}
score += 0.02 * commonPrefixLen;
if (s1.includes(s2) || s2.includes(s1)) {
score += 0.06;
}
return Math.max(0.0, Math.min(1.0, score));
}
function computeTextMatchScore(s1, s2) {
if (s1 === s2) return 1.0;
let dist = levenshteinDistance(s1, s2);
let maxLen = max2(s1.length, s2.length);
if (maxLen === 0) return 1.0;
let full = 1.0 - (dist / maxLen);
let part = s1.length < s2.length ? partialRatio(s1, s2) : partialRatio(s2, s1);
let score = 0.4 * full + 0.6 * part;
let lenDiff = Math.abs(s1.length - s2.length);
if (lenDiff >= 10) {
score -= 0.02 * lenDiff / maxLen;
}
let commonPrefixLen = 0;
let minLen = min2(s1.length, s2.length);
for (let i = 0; i < minLen; i++) {
if (s1[i] === s2[i]) {
commonPrefixLen++;
} else {
break;
}
}
score += 0.01 * commonPrefixLen;
if (s1.includes(s2) || s2.includes(s1)) {
score += 0.2;
}
return Math.max(0.0, Math.min(1.0, score));
}
@@ -1,49 +0,0 @@
import QtQuick
import QtQuick.Shapes
/**
* Draws a hexagon when width == height.
* Otherwise the hexagon is extended
*/
Item {
id: root
property real radius: Math.min(width, height) / 2
property real cornerRounding: radius * 0.5
property color color: "#b7eb34"
property real borderWidth: cornerRounding
property color borderColor: color
Shape {
id: hexShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
id: hexPath
fillColor: root.color
strokeColor: root.borderColor
strokeWidth: root.borderWidth
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
property real r: root.radius
property real r60: r * Math.sqrt(3) / 2
property real r30: r / 2
property real cr: root.cornerRounding
property real cr60: cr * Math.sqrt(3) / 2
property real cr30: cr / 2
property real lineWidthAdjustment: strokeWidth / 2
property real lineWidthAdjustment60: lineWidthAdjustment * Math.sqrt(3) / 2
property real lineWidthAdjustment30: lineWidthAdjustment / 2
startX: hexPath.r; startY: lineWidthAdjustment;
PathLine { x: hexPath.r + hexPath.r60 - hexPath.lineWidthAdjustment60; y: hexShape.height / 2 - hexPath.r30 + hexPath.lineWidthAdjustment30 }
PathLine { x: hexPath.r + hexPath.r60 - hexPath.lineWidthAdjustment60; y: hexShape.height / 2 + hexPath.r30 - hexPath.lineWidthAdjustment30 }
PathLine { x: hexPath.r; y: hexShape.height - hexPath.lineWidthAdjustment }
PathLine { x: hexPath.r - hexPath.r60 + hexPath.lineWidthAdjustment60; y: hexShape.height - hexPath.r30 - hexPath.lineWidthAdjustment30 }
PathLine { x: hexPath.r - hexPath.r60 + hexPath.lineWidthAdjustment60; y: hexPath.r30 + hexPath.lineWidthAdjustment30 }
// Close the path
PathLine { x: hexPath.r; y: hexPath.lineWidthAdjustment }
}
}
}
@@ -1,33 +0,0 @@
import qs.singletons
import QtQuick
Text {
id: root
property real iconSize: Appearance?.font.pixelSize.small ?? 16
property real fill: 0
property real truncatedFill: Math.round(fill * 100) / 100 // Reduce memory consumption spikes from constant font remapping
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
font {
hintingPreference: Font.PreferFullHinting
family: Appearance?.font.family.iconMaterial ?? "Material Symbols Outlined"
pixelSize: iconSize
weight: Font.Normal + (Font.DemiBold - Font.Normal) * fill
variableAxes: {
"FILL": truncatedFill,
// "wght": font.weight,
// "GRAD": 0,
"opsz": iconSize,
}
}
color: Appearance.m3colors.m3onBackground
// Behavior on fill {
// NumberAnimation {
// duration: Appearance?.animation.elementMoveFast.duration ?? 200
// easing.type: Appearance?.animation.elementMoveFast.type ?? Easing.BezierSpline
// easing.bezierCurve: Appearance?.animation.elementMoveFast.bezierCurve ?? [0.34, 0.80, 0.34, 1.00, 1, 1]
// }
// }
}
@@ -1,46 +0,0 @@
import QtQuick
/**
* Draws an octagon when width == height.
* Otherwise it's a rectangle "rounded" with two edges each corner (like 1/4 of an octagon)
*/
Item {
id: root
property real radius: Math.min(width, height) / 2
property color color: "#b7eb34"
onWidthChanged: polyRect.requestPaint()
onHeightChanged: polyRect.requestPaint()
onRadiusChanged: polyRect.requestPaint()
onColorChanged: polyRect.requestPaint()
Canvas {
id: polyRect
anchors.fill: parent
onPaint: {
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
var r = root.radius;
var r45 = r * Math.SQRT2 / 2;
ctx.beginPath();
ctx.moveTo(r, 0);
ctx.lineTo(width - r, 0);
ctx.lineTo(width - r + r45, r - r45);
ctx.lineTo(width, r);
ctx.lineTo(width, height - r);
ctx.lineTo(width - r + r45, height - r + r45);
ctx.lineTo(width - r, height);
ctx.lineTo(r, height);
ctx.lineTo(r - r45, height - r + r45);
ctx.lineTo(0, height - r);
ctx.lineTo(0, r);
ctx.lineTo(r - r45, r - r45);
ctx.closePath();
ctx.fillStyle = root.color;
ctx.fill();
}
}
}
@@ -1,15 +0,0 @@
import qs.singletons
import QtQuick
import QtQuick.Layouts
Text {
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
font {
hintingPreference: Font.PreferFullHinting
family: Appearance?.font.family.main ?? "sans-serif"
pixelSize: Appearance?.font.pixelSize.small ?? 15
}
color: Appearance?.colors.on_background ?? "black"
linkColor: Appearance?.colors.primary ?? "blue"
}
@@ -1,120 +0,0 @@
#!/usr/bin/env python3
import argparse
import cv2
import json
import numpy as np
import sys
DEFAULT_IMAGE_PATH = '/tmp/quickshell/media/screenshot/image'
def iou(boxA, boxB):
# Compute intersection over union for two boxes
xA = max(boxA['x'], boxB['x'])
yA = max(boxA['y'], boxB['y'])
xB = min(boxA['x'] + boxA['width'], boxB['x'] + boxB['width'])
yB = min(boxA['y'] + boxA['height'], boxB['y'] + boxB['height'])
interW = max(0, xB - xA)
interH = max(0, yB - yA)
interArea = interW * interH
boxAArea = boxA['width'] * boxA['height']
boxBArea = boxB['width'] * boxB['height']
iou = interArea / float(boxAArea + boxBArea - interArea) if (boxAArea + boxBArea - interArea) > 0 else 0
return iou
def non_max_suppression(regions, iou_threshold=0.7):
# Sort by area (largest first)
regions = sorted(regions, key=lambda r: r['width'] * r['height'], reverse=True)
keep = []
while regions:
current = regions.pop(0)
keep.append(current)
regions = [r for r in regions if iou(current, r) < iou_threshold]
return keep
def find_regions(image_path, min_width, min_height, max_width=None, max_height=None, quality=False, k=150, min_size=20, sigma=0.8, resize_factor=1.0):
image = cv2.imread(image_path)
if image is None:
print(f'Error: Could not load image {image_path}', file=sys.stderr)
sys.exit(1)
orig_h, orig_w = image.shape[:2]
if resize_factor != 1.0:
image = cv2.resize(image, (int(orig_w * resize_factor), int(orig_h * resize_factor)), interpolation=cv2.INTER_AREA)
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
ss.setBaseImage(image)
if quality:
ss.switchToSelectiveSearchQuality(k, min_size, sigma)
else:
ss.switchToSelectiveSearchFast(k, min_size, sigma)
rects = ss.process()
regions = []
for (x, y, w, h) in rects:
# Scale regions back to original image size if resized
if resize_factor != 1.0:
x = int(x / resize_factor)
y = int(y / resize_factor)
w = int(w / resize_factor)
h = int(h / resize_factor)
# Filter out region that is exactly the same size as the original image
if w == orig_w and h == orig_h and x == 0 and y == 0:
continue
if w > min_width and h > min_height:
if (max_width is None or w < max_width) and (max_height is None or h < max_height):
regions.append({'x': int(x), 'y': int(y), 'width': int(w), 'height': int(h)})
# Remove duplicates/overlaps
regions = non_max_suppression(regions, iou_threshold=0.7)
return regions, cv2.imread(image_path) # Return original image for drawing
def draw_regions(image, regions, output_path):
for region in regions:
if 'x' in region:
x, y, w, h = region['x'], region['y'], region['width'], region['height']
elif 'at' in region and 'size' in region:
x, y = region['at']
w, h = region['size']
else:
continue
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.imwrite(output_path, image)
def main():
parser = argparse.ArgumentParser(description='Find regions of interest in an image using selective search.')
parser.add_argument('-i', '--image', default=DEFAULT_IMAGE_PATH, help='Path to input image')
parser.add_argument('-do', '--debug-output', help='Path to save debug image with rectangles')
parser.add_argument('--min-width', type=int, default=200, help='Minimum width of detected region')
parser.add_argument('--min-height', type=int, default=100, help='Minimum height of detected region')
parser.add_argument('--max-width', type=int, help='Maximum width of detected region')
parser.add_argument('--max-height', type=int, help='Maximum height of detected region')
parser.add_argument('--single', action='store_true', help='Only output the most likely (largest) region')
parser.add_argument('--quality', action='store_true', help='Use quality mode for selective search (slower, less sensitive)')
parser.add_argument('--k', type=int, default=3000, help='Segmentation parameter k (default: 150)')
parser.add_argument('--min-size', type=int, default=50, help='Segmentation parameter min_size (default: 20)')
parser.add_argument('--sigma', type=float, default=0.6, help='Segmentation parameter sigma (default: 0.8)')
parser.add_argument('--resize-factor', type=float, default=0.1, help='Resize factor for input image before processing (default: 1.0, e.g. 0.5 for half size)')
parser.add_argument('--hyprctl', action='store_true', help='Mimics hyprctl\'s window output, like {"at": [x, y], "size": [w, h]}')
args = parser.parse_args()
regions, image = find_regions(
args.image,
min_width=args.min_width,
min_height=args.min_height,
max_width=args.max_width,
max_height=args.max_height,
quality=args.quality,
k=args.k,
min_size=args.min_size,
sigma=args.sigma,
resize_factor=args.resize_factor
)
if args.single and regions:
largest = max(regions, key=lambda r: r['width'] * r['height'])
regions = [largest]
if args.hyprctl:
regions = [{"at": [r['x'], r['y']], "size": [r['width'], r['height']]} for r in regions]
print(json.dumps(regions))
if args.debug_output:
draw_regions(image, regions, args.debug_output)
if __name__ == '__main__':
main()
-24
View File
@@ -1,24 +0,0 @@
//@ pragma UseQApplication
//@ pragma Env QS_NO_RELOAD_POPUP=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Basic
// Adjust this to make the shell smaller or larger
//@ pragma Env QT_SCALE_FACTOR=1
import QtQuick
import QtQuick.Window
import Quickshell
import qs.singletons
import "./modules/background/"
import "./modules/bar/"
ShellRoot {
// Some initialization
Component.onCompleted: {
MaterialThemeLoader.reapplyTheme()
}
Background {}
Bar {}
}
@@ -1,269 +0,0 @@
import QtQuick
import Quickshell
import qs.modules.common.functions
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
property QtObject m3colors
property QtObject animation
property QtObject animationCurves
property QtObject colors
property QtObject rounding
property QtObject font
property QtObject sizes
property string syntaxHighlightingTheme
// Extremely conservative transparency values for consistency and readability
// property real transparency: m3colors.darkmode ? 0.2 : 0.1
// property real contentTransparency: m3colors.darkmode ? 0.55 : 0.55
property real transparency: 0
property real contentTransparency: 0
property color absoluteBackground: m3colors.darkmode ? "#000000" : "#FFFFFF"
m3colors: QtObject {
property bool darkmode: false
property bool transparent: false
property color m3primary_paletteKeyColor: "#91689E"
property color m3secondary_paletteKeyColor: "#837186"
property color m3tertiary_paletteKeyColor: "#9D6A67"
property color m3neutral_paletteKeyColor: "#7C757B"
property color m3neutral_variant_paletteKeyColor: "#7D747D"
property color m3background: "#161217"
property color m3onBackground: "#EAE0E7"
property color m3surface: "#161217"
property color m3surfaceDim: "#161217"
property color m3surfaceBright: "#3D373D"
property color m3surfaceContainerLowest: "#110D12"
property color m3surfaceContainerLow: "#1F1A1F"
property color m3surfaceContainer: "#231E23"
property color m3surfaceContainerHigh: "#2D282E"
property color m3surfaceContainerHighest: "#383339"
property color m3onSurface: "#EAE0E7"
property color m3surfaceVariant: "#4C444D"
property color m3onSurfaceVariant: "#CFC3CD"
property color m3inverseSurface: "#EAE0E7"
property color m3inverseOnSurface: "#342F34"
property color m3outline: "#988E97"
property color m3outlineVariant: "#4C444D"
property color m3shadow: "#000000"
property color m3scrim: "#000000"
property color m3surfaceTint: "#E5B6F2"
property color m3primary: "#E5B6F2"
property color m3onPrimary: "#452152"
property color m3primaryContainer: "#5D386A"
property color m3onPrimaryContainer: "#F9D8FF"
property color m3inversePrimary: "#775084"
property color m3secondary: "#D5C0D7"
property color m3onSecondary: "#392C3D"
property color m3secondaryContainer: "#534457"
property color m3onSecondaryContainer: "#F2DCF3"
property color m3tertiary: "#F5B7B3"
property color m3onTertiary: "#4C2523"
property color m3tertiaryContainer: "#BA837F"
property color m3onTertiaryContainer: "#000000"
property color m3error: "#FFB4AB"
property color m3onError: "#690005"
property color m3errorContainer: "#93000A"
property color m3onErrorContainer: "#FFDAD6"
property color m3primaryFixed: "#F9D8FF"
property color m3primaryFixedDim: "#E5B6F2"
property color m3onPrimaryFixed: "#2E0A3C"
property color m3onPrimaryFixedVariant: "#5D386A"
property color m3secondaryFixed: "#F2DCF3"
property color m3secondaryFixedDim: "#D5C0D7"
property color m3onSecondaryFixed: "#241727"
property color m3onSecondaryFixedVariant: "#514254"
property color m3tertiaryFixed: "#FFDAD7"
property color m3tertiaryFixedDim: "#F5B7B3"
property color m3onTertiaryFixed: "#331110"
property color m3onTertiaryFixedVariant: "#663B39"
property color m3success: "#B5CCBA"
property color m3onSuccess: "#213528"
property color m3successContainer: "#374B3E"
property color m3onSuccessContainer: "#D1E9D6"
property color term0: "#EDE4E4"
property color term1: "#B52755"
property color term2: "#A97363"
property color term3: "#AF535D"
property color term4: "#A67F7C"
property color term5: "#B2416B"
property color term6: "#8D76AD"
property color term7: "#272022"
property color term8: "#0E0D0D"
property color term9: "#B52755"
property color term10: "#A97363"
property color term11: "#AF535D"
property color term12: "#A67F7C"
property color term13: "#B2416B"
property color term14: "#8D76AD"
property color term15: "#221A1A"
}
colors: QtObject {
property color colSubtext: m3colors.m3outline
property color colLayer0: ColorUtils.transparentize(ColorUtils.mix(m3colors.m3background, root.absoluteBackground, 0.5), root.transparency)
property color colOnLayer0: m3colors.m3onBackground
property color colLayer0Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.9, root.contentTransparency))
property color colLayer0Active: ColorUtils.transparentize(ColorUtils.mix(colLayer0, colOnLayer0, 0.8, root.contentTransparency))
property color colLayer1: ColorUtils.transparentize(ColorUtils.mix(m3colors.m3surfaceContainerLow, m3colors.m3background, 0.8), root.contentTransparency);
property color colOnLayer1: m3colors.m3onSurfaceVariant;
property color colOnLayer1Inactive: ColorUtils.mix(colOnLayer1, colLayer1, 0.45);
property color colLayer2: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.contentTransparency)
property color colLayer2Border: ColorUtils.mix(colLayer2, m3colors.m3outline, 0.8);
property color colOnLayer2: m3colors.m3onSurface;
property color colOnLayer2Disabled: ColorUtils.mix(colOnLayer2, m3colors.m3background, 0.4);
property color colLayer3: ColorUtils.transparentize(ColorUtils.mix(m3colors.m3surfaceContainerHigh, m3colors.m3onSurface, 0.96), root.contentTransparency)
property color colOnLayer3: m3colors.m3onSurface;
property color colLayer1Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer1, colOnLayer1, 0.92), root.contentTransparency)
property color colLayer1Active: ColorUtils.transparentize(ColorUtils.mix(colLayer1, colOnLayer1, 0.85), root.contentTransparency);
property color colLayer2Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer2, colOnLayer2, 0.90), root.contentTransparency)
property color colLayer2Active: ColorUtils.transparentize(ColorUtils.mix(colLayer2, colOnLayer2, 0.80), root.contentTransparency);
property color colLayer2Disabled: ColorUtils.transparentize(ColorUtils.mix(colLayer2, m3colors.m3background, 0.8), root.contentTransparency);
property color colLayer3Hover: ColorUtils.transparentize(ColorUtils.mix(colLayer3, colOnLayer3, 0.90), root.contentTransparency)
property color colLayer3Active: ColorUtils.transparentize(ColorUtils.mix(colLayer3, colOnLayer3, 0.80), root.contentTransparency);
property color colPrimary: m3colors.m3primary
property color colOnPrimary: m3colors.m3onPrimary
property color colPrimaryHover: ColorUtils.mix(colors.colPrimary, colLayer1Hover, 0.87)
property color colPrimaryActive: ColorUtils.mix(colors.colPrimary, colLayer1Active, 0.7)
property color colPrimaryContainer: m3colors.m3primaryContainer
property color colPrimaryContainerHover: ColorUtils.mix(colors.colPrimaryContainer, colLayer1Hover, 0.7)
property color colPrimaryContainerActive: ColorUtils.mix(colors.colPrimaryContainer, colLayer1Active, 0.6)
property color colOnPrimaryContainer: m3colors.m3onPrimaryContainer
property color colSecondary: m3colors.m3secondary
property color colSecondaryHover: ColorUtils.mix(m3colors.m3secondary, colLayer1Hover, 0.85)
property color colSecondaryActive: ColorUtils.mix(m3colors.m3secondary, colLayer1Active, 0.4)
property color colSecondaryContainer: m3colors.m3secondaryContainer
property color colSecondaryContainerHover: ColorUtils.mix(m3colors.m3secondaryContainer, m3colors.m3onSecondaryContainer, 0.90)
property color colSecondaryContainerActive: ColorUtils.mix(m3colors.m3secondaryContainer, colLayer1Active, 0.54)
property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer
property color colSurfaceContainerLow: ColorUtils.transparentize(m3colors.m3surfaceContainerLow, root.contentTransparency)
property color colSurfaceContainer: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.contentTransparency)
property color colSurfaceContainerHigh: ColorUtils.transparentize(m3colors.m3surfaceContainerHigh, root.contentTransparency)
property color colSurfaceContainerHighest: ColorUtils.transparentize(m3colors.m3surfaceContainerHighest, root.contentTransparency)
property color colSurfaceContainerHighestHover: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.95)
property color colSurfaceContainerHighestActive: ColorUtils.mix(m3colors.m3surfaceContainerHighest, m3colors.m3onSurface, 0.85)
property color colTooltip: m3colors.darkmode ? ColorUtils.mix(m3colors.m3background, "#3C4043", 0.5) : "#3C4043" // m3colors.m3inverseSurface in the specs, but the m3 website actually uses #3C4043
property color colOnTooltip: "#F8F9FA" // m3colors.m3inverseOnSurface in the specs, but the m3 website actually uses this color
property color colScrim: ColorUtils.transparentize(m3colors.m3scrim, 0.5)
property color colShadow: ColorUtils.transparentize(m3colors.m3shadow, 0.7)
property color colOutline: ColorUtils.mix(m3colors.m3outline, m3colors.m3background, 0.7)
property color colOutlineVariant: ColorUtils.mix(m3colors.m3outlineVariant, m3colors.m3background, 0.5)
}
rounding: QtObject {
property int unsharpen: 2
property int unsharpenmore: 6
property int verysmall: 8
property int small: 12
property int normal: 17
property int large: 23
property int verylarge: 30
property int full: 9999
property int screenRounding: large
property int windowRounding: 18
}
font: QtObject {
property QtObject family: QtObject {
property string main: "Geist"
property string title: "Gabarito"
property string iconMaterial: "Material Symbols Outlined"
property string iconNerd: "SpaceMono NF"
property string monospace: "JetBrains Mono NF"
property string reading: "Readex Pro"
property string expressive: "Space Grotesk"
}
property QtObject pixelSize: QtObject {
property int smallest: 10
property int smaller: 12
property int small: 15
property int normal: 16
property int large: 17
property int larger: 19
property int huge: 22
property int hugeass: 23
property int title: huge
}
}
animationCurves: QtObject {
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] // Default, 350ms
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1] // Default, 500ms
readonly property list<real> expressiveSlowSpatial: [0.39, 1.29, 0.35, 0.98, 1, 1] // Default, 650ms
readonly property list<real> expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1] // Default, 200ms
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedFirstHalf: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82]
readonly property list<real> emphasizedLastHalf: [5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
readonly property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
readonly property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
readonly property real expressiveFastSpatialDuration: 350
readonly property real expressiveDefaultSpatialDuration: 500
readonly property real expressiveSlowSpatialDuration: 650
readonly property real expressiveEffectsDuration: 200
}
animation: QtObject {
property QtObject elementMove: QtObject {
property int duration: 300
property int type: Easing.BezierSpline
property list<real> bezierCurve: animationCurves.standardDecel
property int velocity: 650
property Component numberAnimation: Component {
NumberAnimation {
duration: root.animation.elementMove.duration
easing.type: root.animation.elementMove.type
easing.bezierCurve: root.animation.elementMove.bezierCurve
}
}
property Component colorAnimation: Component {
ColorAnimation {
duration: root.animation.elementMove.duration
easing.type: root.animation.elementMove.type
easing.bezierCurve: root.animation.elementMove.bezierCurve
}
}
}
property QtObject elementMoveEnter: QtObject {
property int duration: 400
property int type: Easing.BezierSpline
property list<real> bezierCurve: animationCurves.emphasizedDecel
property int velocity: 650
property Component numberAnimation: Component {
NumberAnimation {
duration: root.animation.elementMoveEnter.duration
easing.type: root.animation.elementMoveEnter.type
easing.bezierCurve: root.animation.elementMoveEnter.bezierCurve
}
}
}
property QtObject elementMoveFast: QtObject {
property int duration: 175
property int type: Easing.BezierSpline
property list<real> bezierCurve: animationCurves.expressiveEffects
property int velocity: 850
property Component colorAnimation: Component { ColorAnimation {
duration: 70
easing.type: root.animation.elementMoveFast.type
easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
}}
property Component numberAnimation: Component { NumberAnimation {
duration: root.animation.elementMoveFast.duration
easing.type: root.animation.elementMoveFast.type
easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
}}
}
}
sizes: QtObject {
property real hyprlandGapsOut: 5
property real barHeight: 46
property real barBorder: 1
}
syntaxHighlightingTheme: Appearance.m3colors.darkmode ? "Monokai" : "ayu Light"
}
@@ -1,76 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string configFilePath: Directories.shellConfigPath
property alias options: configOptionsJsonAdapter
function setNestedValue(nestedKey, value) {
let keys = nestedKey.split(".");
let obj = root.options;
let parents = [obj];
// Traverse and collect parent objects
for (let i = 0; i < keys.length - 1; ++i) {
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
obj[keys[i]] = {};
}
obj = obj[keys[i]];
parents.push(obj);
}
// Convert value to correct type using JSON.parse when safe
let convertedValue = value;
if (typeof value === "string") {
let trimmed = value.trim();
if (trimmed === "true" || trimmed === "false" || !isNaN(Number(trimmed))) {
try {
convertedValue = JSON.parse(trimmed);
} catch (e) {
convertedValue = value;
}
}
}
obj[keys[keys.length - 1]] = convertedValue;
}
FileView {
path: root.configFilePath
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: writeAdapter()
onLoadFailed: error => {
if (error == FileViewError.FileNotFound) {
writeAdapter();
}
}
JsonAdapter {
id: configOptionsJsonAdapter
property JsonObject background: JsonObject {
property bool fixedClockPosition: false
property real clockX: -500
property real clockY: -500
property string wallpaperPath: ""
property JsonObject parallax: JsonObject {
property bool enableWorkspace: true
property real workspaceZoom: 1.07 // Relative to your screen, not wallpaper size
property bool enableSidebar: true
}
}
property JsonObject time: JsonObject {
// https://doc.qt.io/qt-6/qtime.html#toString
property string format: "hh:mm"
property string dateFormat: "ddd, dd/MM"
}
}
}
}
@@ -1,52 +0,0 @@
import qs.singletons
import QtQuick
import Quickshell
import Quickshell.Io
pragma Singleton
pragma ComponentBehavior: Bound
/**
* A nice wrapper for date and time strings.
*/
Singleton {
property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm")
property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM")
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
property string uptime: "0h, 0m"
SystemClock {
id: clock
precision: SystemClock.Minutes
}
Timer {
interval: 10
running: true
repeat: true
onTriggered: {
fileUptime.reload()
const textUptime = fileUptime.text()
const uptimeSeconds = Number(textUptime.split(" ")[0] ?? 0)
// Convert seconds to days, hours, and minutes
const days = Math.floor(uptimeSeconds / 86400)
const hours = Math.floor((uptimeSeconds % 86400) / 3600)
const minutes = Math.floor((uptimeSeconds % 3600) / 60)
// Build the formatted uptime string
let formatted = ""
if (days > 0) formatted += `${days}d`
if (hours > 0) formatted += `${formatted ? ", " : ""}${hours}h`
if (minutes > 0 || !formatted) formatted += `${formatted ? ", " : ""}${minutes}m`
uptime = formatted
interval = Config.options?.resources?.updateInterval ?? 3000
}
}
FileView {
id: fileUptime
path: "/proc/uptime"
}
}
@@ -1,30 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import qs.modules.common.functions
import Qt.labs.platform
import QtQuick
import Quickshell
Singleton {
// XDG Dirs, with "file://"
readonly property string config: StandardPaths.standardLocations(StandardPaths.ConfigLocation)[0]
readonly property string state: StandardPaths.standardLocations(StandardPaths.StateLocation)[0]
readonly property string cache: StandardPaths.standardLocations(StandardPaths.CacheLocation)[0]
readonly property string pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
readonly property string downloads: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
// Other dirs used by the shell, without "file://"
property string assetsPath: Quickshell.shellPath("assets")
property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.state}/user/generated/colors.json`)
property string notificationsPath: FileUtils.trimFileProtocol(`${Directories.cache}/notifications/notifications.json`)
property string scriptPath: Quickshell.shellPath("scripts")
property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/quickshell`)
property string shellConfigName: "oo.json"
property string shellConfigPath: `${Directories.shellConfig}/${Directories.shellConfigName}`
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`)
// Cleanup on init
Component.onCompleted: {
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`])
}
}
@@ -1,57 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
/**
* Automatically reloads generated material colors.
* It is necessary to run reapplyTheme() on startup because Singletons are lazily loaded.
*/
Singleton {
id: root
property string filePath: Directories.generatedMaterialThemePath
function reapplyTheme() {
themeFileView.reload()
}
function applyColors(fileContent) {
const json = JSON.parse(fileContent)
for (const key in json) {
if (json.hasOwnProperty(key)) {
// Convert snake_case to CamelCase
const camelCaseKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase())
const m3Key = `m3${camelCaseKey}`
Appearance.m3colors[m3Key] = json[key]
}
}
Appearance.m3colors.darkmode = (Appearance.m3colors.m3background.hslLightness < 0.5)
}
Timer {
id: delayedFileRead
interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100
repeat: false
running: false
onTriggered: {
root.applyColors(themeFileView.text())
}
}
FileView {
id: themeFileView
path: Qt.resolvedUrl(root.filePath)
watchChanges: true
onFileChanged: {
this.reload()
delayedFileRead.start()
}
onLoadedChanged: {
const fileContent = themeFileView.text()
root.applyColors(fileContent)
}
}
}
-314
View File
@@ -1,314 +0,0 @@
{
"Mo": "Mo/*keep*/",
"Tu": "Tu/*keep*/",
"We": "We/*keep*/",
"Th": "Th/*keep*/",
"Fr": "Fr/*keep*/",
"Sa": "Sa/*keep*/",
"Su": "Su/*keep*/",
"%1 characters": "%1 characters",
"**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key",
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key",
". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!": ". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!",
"<i>No further instruction provided</i>": "<i>No further instruction provided</i>",
"Action": "Action",
"Add": "Add",
"Add task": "Add task",
"All-rounder | Good quality, decent quantity": "All-rounder | Good quality, decent quantity",
"Allow NSFW": "Allow NSFW",
"Allow NSFW content": "Allow NSFW content",
"Anime": "Anime",
"Anime boorus": "Anime boorus",
"App": "App",
"Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel": "Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel",
"Bluetooth": "Bluetooth",
"Brightness": "Brightness",
"Cancel": "Cancel",
"Chain of Thought": "Chain of Thought",
"Cheat sheet": "Cheat sheet",
"Choose model": "Choose model",
"Clean stuff | Excellent quality, no NSFW": "Clean stuff | Excellent quality, no NSFW",
"Clear": "Clear",
"Clear chat history": "Clear chat history",
"Clear the current list of images": "Clear the current list of images",
"Close": "Close",
"Copy": "Copy",
"Copy code": "Copy code",
"Delete": "Delete",
"Desktop": "Desktop",
"Disable NSFW content": "Disable NSFW content",
"Done": "Done",
"Download": "Download",
"Edit": "Edit",
"Enter text to translate...": "Enter text to translate...",
"Finished tasks will go here": "Finished tasks will go here",
"For desktop wallpapers | Good quality": "For desktop wallpapers | Good quality",
"For storing API keys and other sensitive information": "For storing API keys and other sensitive information",
"Game mode": "Game mode",
"Get the next page of results": "Get the next page of results",
"Hibernate": "Hibernate",
"Input": "Input",
"Intelligence": "Intelligence",
"Interface": "Interface",
"Invalid arguments. Must provide `key` and `value`.": "Invalid arguments. Must provide `key` and `value`.",
"Jump to current month": "Jump to current month",
"Keep system awake": "Keep system awake",
"Large images | God tier quality, no NSFW.": "Large images | God tier quality, no NSFW.",
"Large language models": "Large language models",
"Launch": "Launch",
"Lock": "Lock",
"Logout": "Logout",
"Markdown test": "Markdown test",
"Math result": "Math result",
"Night Light": "Night Light",
"No audio source": "No audio source",
"No media": "No media",
"No notifications": "No notifications",
"Not visible to model": "Not visible to model",
"Nothing here!": "Nothing here!",
"Notifications": "Notifications",
"OK": "OK",
"Open file link": "Open file link",
"Output": "Output",
"Reboot": "Reboot",
"Reboot to firmware settings": "Reboot to firmware settings",
"Reload Hyprland & Quickshell": "Reload Hyprland & Quickshell",
"Run": "Run",
"Run command": "Run command",
"Save": "Save",
"Save to Downloads": "Save to Downloads",
"Search": "Search",
"Search the web": "Search the web",
"Search, calculate or run": "Search, calculate or run",
"Select Language": "Select Language",
"Session": "Session",
"Set API key": "Set API key",
"Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.",
"Set the current API provider": "Set the current API provider",
"Shutdown": "Shutdown",
"Silent": "Silent",
"Sleep": "Sleep",
"System": "System",
"Task Manager": "Task Manager",
"Task description": "Task description",
"Temperature must be between 0 and 2": "Temperature must be between 0 and 2",
"The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "The hentai one | Great quantity, a lot of NSFW, quality varies wildly",
"The popular one | Best quantity, but quality can vary wildly": "The popular one | Best quantity, but quality can vary wildly",
"Thinking": "Thinking",
"Translation goes here...": "Translation goes here...",
"Translator": "Translator",
"Unfinished": "Unfinished",
"Unknown": "Unknown",
"Unknown Album": "Unknown Album",
"Unknown Artist": "Unknown Artist",
"Unknown Title": "Unknown Title",
"View Markdown source": "View Markdown source",
"Volume": "Volume",
"Volume mixer": "Volume mixer",
"Waifus only | Excellent quality, limited quantity": "Waifus only | Excellent quality, limited quantity",
"Waiting for response...": "Waiting for response...",
"Workspace": "Workspace",
"Set with /mode PROVIDER": "Set with /mode PROVIDER",
"Invalid API provider. Supported: \n-": "Invalid API provider. Supported: \n-",
"Unknown command:": "Unknown command:",
"Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window",
"The current API used. Endpoint:": "The current API used. Endpoint:",
"Provider set to": "Provider set to",
"Invalid model. Supported: \n```": "Invalid model. Supported: \n```",
"That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number",
"Online | Google's model\nGives up-to-date information with search.": "Online | Google's model\nGives up-to-date information with search.",
"Switched to search mode. Continue with the user's request.": "Switched to search mode. Continue with the user's request.",
"Experimental | Online | Google's model\nCan do a little more but doesn't search quickly": "Experimental | Online | Google's model\nCan do a little more but doesn't search quickly",
"Settings": "Settings",
"Save chat": "Save chat",
"Load chat": "Load chat",
"or": "or",
"Set the system prompt for the model.": "Set the system prompt for the model.",
"To Do": "To Do",
"Calendar": "Calendar",
"Advanced": "Advanced",
"About": "About",
"Services": "Services",
"Style": "Style",
"Edit config": "Edit config",
"Colors & Wallpaper": "Colors & Wallpaper",
"Light": "Light",
"Dark": "Dark",
"Material palette": "Material palette",
"Fidelity": "Fidelity",
"Fruit Salad": "Fruit Salad",
"Alternatively use /dark, /light, /img in the launcher": "Alternatively use /dark, /light, /img in the launcher",
"Fake screen rounding": "Fake screen rounding",
"When not fullscreen": "When not fullscreen",
"Choose file": "Choose file",
"Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers": "Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers",
"Be patient...": "Be patient...",
"Decorations & Effects": "Decorations & Effects",
"Tonal Spot": "Tonal Spot",
"Shell windows": "Shell windows",
"Auto": "Auto",
"Wallpaper": "Wallpaper",
"Content": "Content",
"Title bar": "Title bar",
"Transparency": "Transparency",
"Expressive": "Expressive",
"Yes": "Yes",
"Enable": "Enable",
"Rainbow": "Rainbow",
"Might look ass. Unsupported.": "Might look ass. Unsupported.",
"Monochrome": "Monochrome",
"Random: Konachan": "Random: Konachan",
"Center title": "Center title",
"Neutral": "Neutral",
"Pick wallpaper image on your system": "Pick wallpaper image on your system",
"No": "No",
"AI": "AI",
"Local only": "Local only",
"Policies": "Policies",
"Weeb": "Weeb",
"Closet": "Closet",
"Bar style": "Bar style",
"Show next time": "Show next time",
"Usage": "Usage",
"Plain rectangle": "Plain rectangle",
"Useless buttons": "Useless buttons",
"GitHub": "GitHub",
"Style & wallpaper": "Style & wallpaper",
"Configuration": "Configuration",
"Change any time later with /dark, /light, /img in the launcher": "Change any time later with /dark, /light, /img in the launcher",
"Keybinds": "Keybinds",
"Float": "Float",
"Hug": "Hug",
"Yooooo hi there": "Yooooo hi there",
"illogical-impulse Welcome": "illogical-impulse Welcome",
"Info": "Info",
"Volume limit": "Volume limit",
"Prevents abrupt increments and restricts volume limit": "Prevents abrupt increments and restricts volume limit",
"Resources": "Resources",
"12h am/pm": "12h am/pm",
"Base URL": "Base URL",
"Audio": "Audio",
"Networking": "Networking",
"Format": "Format",
"Time": "Time",
"Battery": "Battery",
"Prefixes": "Prefixes",
"Emojis": "Emojis",
"Earbang protection": "Earbang protection",
"Automatically suspends the system when battery is low": "Automatically suspends the system when battery is low",
"Automatic suspend": "Automatic suspend",
"Suspend at": "Suspend at",
"Max allowed increase": "Max allowed increase",
"Web search": "Web search",
"Polling interval (ms)": "Polling interval (ms)",
"Clipboard": "Clipboard",
"Low warning": "Low warning",
"24h": "24h",
"Use Levenshtein distance-based algorithm instead of fuzzy": "Use Levenshtein distance-based algorithm instead of fuzzy",
"System prompt": "System prompt",
"12h AM/PM": "12h AM/PM",
"Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)": "Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)",
"Critical warning": "Critical warning",
"User agent (for services that require it)": "User agent (for services that require it)",
"Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.": "Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.",
"Note: turning off can hurt readability": "Note: turning off can hurt readability",
"Workspaces shown": "Workspaces shown",
"Dark/Light toggle": "Dark/Light toggle",
"Dock": "Dock",
"Weather": "Weather",
"Pinned on startup": "Pinned on startup",
"Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience": "Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience",
"Appearance": "Appearance",
"Always show numbers": "Always show numbers",
"Buttons": "Buttons",
"Keyboard toggle": "Keyboard toggle",
"Scale (%)": "Scale (%)",
"Overview": "Overview",
"Rows": "Rows",
"Borderless": "Borderless",
"Screenshot tool": "Screenshot tool",
"Number show delay when pressing Super (ms)": "Number show delay when pressing Super (ms)",
"Timeout (ms)": "Timeout (ms)",
"Show app icons": "Show app icons",
"Workspaces": "Workspaces",
"Columns": "Columns",
"On-screen display": "On-screen display",
"Screen snip": "Screen snip",
"Mic toggle": "Mic toggle",
"Hover to reveal": "Hover to reveal",
"Bar": "Bar",
"Show background": "Show background",
"Show regions of potential interest": "Show regions of potential interest",
"Color picker": "Color picker",
"Help & Support": "Help & Support",
"Discussions": "Discussions",
"Color generation": "Color generation",
"Dotfiles": "Dotfiles",
"Distro": "Distro",
"Privacy Policy": "Privacy Policy",
"Documentation": "Documentation",
"Shell & utilities theming must also be enabled": "Shell & utilities theming must also be enabled",
"illogical-impulse": "illogical-impulse",
"Donate": "Donate",
"Terminal": "Terminal",
"Shell & utilities": "Shell & utilities",
"Qt apps": "Qt apps",
"Report a Bug": "Report a Bug",
"Issues": "Issues",
"Drag or click a region • LMB: Copy • RMB: Edit": "Drag or click a region • LMB: Copy • RMB: Edit",
"Current model: %1\nSet it with %2model MODEL": "Current model: %1\nSet it with %2model MODEL",
"Message the model... \"%1\" for commands": "Message the model... \"%1\" for commands",
"No API key set for %1": "No API key set for %1",
"Loaded the following system prompt\n\n---\n\n%1": "Loaded the following system prompt\n\n---\n\n%1",
"%1 | Right-click to configure": "%1 | Right-click to configure",
"API key set for %1": "API key set for %1",
"Online via %1 | %2's model": "Online via %1 | %2's model",
"Current API endpoint: %1\nSet it with %2mode PROVIDER": "Current API endpoint: %1\nSet it with %2mode PROVIDER",
"Go to source (%1)": "Go to source (%1)",
"Temperature set to %1": "Temperature set to %1",
"To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3": "To set an API key, pass it with the command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3",
"Enter tags, or \"%1\" for commands": "Enter tags, or \"%1\" for commands",
"%1 queries pending": "%1 queries pending",
"API key:\n\n```txt\n%1\n```": "API key:\n\n```txt\n%1\n```",
"Uptime: %1": "Uptime: %1",
"%1 Safe Storage": "%1 Safe Storage",
"%1 does not require an API key": "%1 does not require an API key",
"Temperature: %1": "Temperature: %1",
"Model set to %1": "Model set to %1",
"Page %1": "Page %1",
"Local Ollama model | %1": "Local Ollama model | %1",
"The current system prompt is\n\n---\n\n%1": "The current system prompt is\n\n---\n\n%1",
"Unknown function call: %1": "Unknown function call: %1",
"%1 notifications": "%1 notifications",
"Load chat from %1": "Load chat from %1",
"Load prompt from %1": "Load prompt from %1",
"Save chat to %1": "Save chat to %1",
"Weather Service": "Weather Service",
"Cannot find a GPS service. Using the fallback method instead.": "Cannot find a GPS service. Using the fallback method instead.",
"Critically low battery": "Critically low battery",
"Select output device": "Select output device",
"Code saved to file": "Code saved to file",
"Online models disallowed\n\nControlled by `policies.ai` config option": "Online models disallowed\n\nControlled by `policies.ai` config option",
"Scroll to change volume": "Scroll to change volume",
"Elements": "Elements",
"%1 • %2 tasks": "%1 • %2 tasks",
"Download complete": "Download complete",
"Please charge!\nAutomatic suspend triggers at %1": "Please charge!\nAutomatic suspend triggers at %1",
"Cloudflare WARP": "Cloudflare WARP",
"Cloudflare WARP (1.1.1.1)": "Cloudflare WARP (1.1.1.1)",
"Scroll to change brightness": "Scroll to change brightness",
"Connection failed. Please inspect manually with the <tt>warp-cli</tt> command": "Connection failed. Please inspect manually with the <tt>warp-cli</tt> command",
"Select input device": "Select input device",
"Registration failed. Please inspect manually with the <tt>warp-cli</tt> command": "Registration failed. Please inspect manually with the <tt>warp-cli</tt> command",
"Consider plugging in your device": "Consider plugging in your device",
"Low battery": "Low battery",
"Saved to %1": "Saved to %1",
"Sunset": "Sunset",
"UV Index": "UV Index",
"Humidity": "Humidity",
"Wind": "Wind",
"Sunrise": "Sunrise",
"Pressure": "Pressure",
"Visibility": "Visibility",
"Precipitation": "Precipitation"
}
-2
View File
@@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
+53
View File
@@ -0,0 +1,53 @@
# Contributing
- Please, please, please, make multiple PRs if you have many features/fixes, and don't shove your personal changes along with the PR, including changed defaults
- We can accept features that we do not personally want, but in that case we will ask you to make it configurable/optionally loaded.
- If you want to start working on something big to contribute, it might be a good idea to ask first to not waste your effort (but if you've already done it for yourself, it doesn't hurt to submit).
# Code details
## Contributing to i18n
For contributing in translation (i18n) for Quickshell, see also `dots/.config/quickshell/ii/translations/tools`.
## Dynamic loading
- If something's not always necessary, especially when guarded by a config option to enable/disable, put it in a `Loader`. One tip with `Loader`s is sometimes you will need to declare positioning properties (like `anchors`) in the `Loader`, not the `sourceComponent`.
## Practical concerns
- Make sure what you add does not require significant resources for a minor purpose or harm usability just for the sake of looking nice. The dotfiles must remain practical for daily driving.
- If there is something really fancy and impractical anyway, add a config option for it and make sure it's disabled by default.
# Setting up
The following instruction assumes that you have an Arch(-based) Linux system.
## Complete
_Might not be necessary depending on what you change, but this is recommended._
- [Install](https://ii.clsty.link/en/ii-qs/01setup/) the dotfiles (if you don't wanna replace your stuff completely, do it on a new user).
- Make changes, copy changes to a fork, create PR.
## Partially working shell
_Most stuff in the shell will work but not everything._
- Install Hyprland and the development version of Quickshell (`yay -S hyprland quickshell-git`).
- Copy `dots/.config/quickshell` folder to your home directory.
## Extra setup for Quickshell
- Quickshell-specific LSP setup: Run `touch ~/.config/quickshell/ii/.qmlls.ini` for proper LSP support.
- Hint for VSCode: Get the official "Qt Qml" extension, go to its settings and change custom exe path to `/usr/bin/qmlls6`.
## Python
If your changes involves using python package or script, please use the virtual environment created by uv as described in `sdata/uv/README.md`.
# Running
- Launch Hyprland (not the "uwsm-managed" one)
- For the shell:
- Open `~/.config/quickshell/ii` in your code editor.
- In a terminal run `pkill qs; qs -c ii` to start the shell in the terminal (for logs).
- Make edits in the opened folder. Changes are reloaded live.
+5 -5
View File
@@ -4,21 +4,21 @@ labels: ["ISSUE"]
body:
- type: markdown
attributes:
value: "**Welcome to submit a new issue!**\n- It takes only 3 steps, so please be patient :)\n- Tip: If your issue is not a feature request, and it does not fit into the following form, for example \"how can I edit some widget\", please use [Discussions](https://github.com/end-4/dots-hyprland/discussions) instead."
value: "**Welcome to submit a new issue!**\n- Please search in [existing issues](https://github.com/end-4/dots-hyprland/issues?q=is%3Aissue) before continue.\n- It takes only 3 steps, so please be patient :)\n- NOTE 1: If your issue is not a feature request, and it does not fit into the following form, for example \"how can I edit some widget\", please use [Discussions](https://github.com/end-4/dots-hyprland/discussions) instead.\n- NOTE 2: If your problem is distro specific and you do not use Arch(-based) distros, plesae submit [Discussion at Extra Distros](https://github.com/end-4/dots-hyprland/discussions/new?category=extra-distros) instead."
- type: checkboxes
attributes:
label: "Step 1. Before you submit"
description: "Hint: The 2nd and 3rd checkbox is **not** forcely required as you may have failed to do so."
options:
- label: I have read the [Troubleshooting](https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/04troubleshooting/) and [Usage](https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/02usage/) pages.
- label: I have read the [Troubleshooting](https://ii.clsty.link/en/ii-qs/04troubleshooting/) and [Usage](https://ii.clsty.link/en/ii-qs/02usage/) pages.
required: true
- label: I've successfully updated to the latest version following the [guidance](https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/01setup/#updating).
- label: I've successfully updated to the latest version following the [guidance](https://ii.clsty.link/en/ii-qs/01setup/#updating).
required: false # Not required cuz user may have failed to do so
- label: I've successfully updated the system packages to the latest.
required: false # Not required cuz user may have failed to do so
- label: I've ticked the checkboxes without reading their contents
required: false # Obviously
# TODO: Use GitHub Action to auto add folding tag if the log contains more than 15 lines, instead of tell user to "paste here" cuz many users actually does not know its meaning (It's also not convenient anyway).
- type: textarea
attributes:
label: "Step 2. Quick diagnose info"
@@ -33,7 +33,7 @@ body:
**Tips for the following Step 3**
1. Use `LANG=C LC_ALL=C` to get the output of a command in English, eg. `LANG=C LC_ALL=C date` displays time in English.
2. If it throws errors, **PLEASE**, attach logs and describe in detail if possible.
- Bar and widgets not showing? run `pkill agsv1; agsv1` for logs.
- Bar and widgets not showing? run `pkill qs; qs -c ii` for logs.
- Installation failed? Run installation again for logs.
- You may use more code blocks when needed.
3. In case you are confused, the `<details>`, `<summary>`, `</summary>`, `</details>` are HTML tags for folding the logs (typically very long) inside. Please do not touch them (unless you know what you are doing).

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